# Copyright 2017-2023 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 . # This file is part of the gdb testsuite. load_lib completion-support.exp load_lib data-structures.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 } # Tests below are about tab-completion, which doesn't work if readline # library isn't used. Check it first. if { ![readline_is_used] } { untested "no tab completion support without readline" return -1 } # # Some convenience procedures for testing template parameter list # completion. # # For the variable named ARGLISTVAR, which should be the name of an # argument list in the calling frame, "consume" the top-most token. # [See comments for makefoo for description of arglist format.] proc consume {arglistvar} { upvar $arglistvar arglist # ARGLIST is a string -- simply strip off the first character. set arglist [string range $arglist 1 end] } # Create a function template named NAME, using the given stack ID to grab # NUM template parameters. The result is pushed back onto the # stack. NUM may be "all," in which case we use the entire stack # to create the function template, including function arguments. # The resulting template function's arguments are taken from the test # source code for the function "foo" and is not generalized. proc maket {sid name {num 1}} { # Set up a temporary stack of parameters. This will reverse # the order in SID so that when they are popped again below, # we get them in the correct order. This also takes into account # how many levels of the result stack we want to consider. set paramstack [::Stack::new] if {[string equal $num "all"]} { while {![stack empty $sid]} { stack push $paramstack [stack pop $sid] } } else { for {set i 0} {$i < $num} {incr i} { stack push $paramstack [stack pop $sid] } } # Construct the function template and push it back to the # top of the stack given by SID. set result "" set first true while {![stack empty $paramstack]} { set top [stack pop $paramstack] if {$first} { set first false } else { append result ", " } append result $top } # Save argument list. set args $result # GDB outputs "> >" instead of ">>". if {[string index $top end] == ">"} { append result " " } set result "$name<$result>" if {[string equal $num "all"]} { append result "($args)" } stack push $sid $result stack delete $paramstack } # Given the stack SID and the name of a variable of the desired template # parameters, construct the actual template parameter and push it to the # top of the stack. proc makearg {sid arglistvar} { upvar $arglistvar arglist set c [string index $arglist 0] consume arglist switch $c { A - B { makearg $sid arglist makearg $sid arglist maket $sid $c 2 } a - b - c - d { makearg $sid arglist maket $sid $c } i { stack push $sid "int" } n { # These are not templates. set c [string index $arglist 0] stack push $sid "n::n$c" consume arglist } N { set c [string index $arglist 0] makearg $sid arglist set top [stack pop $sid] stack push $sid "n::N$top" } default { error "unhandled arglist identifier: '$c'" } } } # Given ARGLIST, construct a class template for the type and return # it as a string. proc maketype {arglist} { set s [Stack::new] makearg $s arglist set result [stack pop $s] stack delete $s return $result } # Returns a function template declaration for the function "foo" in the # corresponding test source code. ARGLIST specifies the exact instantiation # that is desired. # # Generically, this procedure returns a string of the form, # "foo (arg-list)", where ARGLIST describes the parameter(s). # # Valid specifiers for ARGLIST (must be kept in sync with source code): # # i: Creates an "int" type. # a, b, c, d: Creates the struct template of the same name, taking a single # template parameter. # A, B: Creates the struct template of the same name, taking two template # parameters. # na, nb: Creates the non-template structs n::na and n::nb, respectively. # NA, NB: Creates the struct templates n::NA and n::NB, respectively, which # take two template parameters. # # Examples: # makefoo i # --> foo (int) # makefoo ii # --> foo (int, int) # makefoo Aiabi # --> foo > > > (A > >) # makefoo NANAiaiNBbiabi # --> foo >, n::NB, a > > > > # (n::NA >, n::NB, a > > >) proc makefoo {arglist} { set s [::Stack::new] while {[string length $arglist] > 0} { makearg $s arglist } maket $s "foo" all set result [stack pop $s] stack delete $s return $result } # Test wrapper for a single "makefoo" unit test. proc test_makefoo_1 {arglist expected} { set exp "foo<$expected" if {[string index $exp end] == ">"} { append exp " " } append exp ">" append exp "($expected)" set calc [makefoo $arglist] send_log "makefoo $arglist = $calc\n" send_log "expecting: $exp\n" if {[string equal $exp $calc]} { pass "makefoo unit test: $arglist" } else { fail "makefoo unit test: $arglist" } } # Test whether the procedure "makefoo" is functioning as expected. proc test_makefoo {} { test_makefoo_1 "i" "int" test_makefoo_1 "ai" "a" test_makefoo_1 "aai" "a >" test_makefoo_1 "ii" "int, int" test_makefoo_1 "aaibi" "a >, b" test_makefoo_1 \ "ababiibababai" "a > > >, int, b > > > > >" test_makefoo_1 "Aii" "A" test_makefoo_1 "ABaibibi" "A, b >, b >" test_makefoo_1 "na" "n::na" test_makefoo_1 "nana" "n::na, n::na" test_makefoo_1 "NAii" "n::NA" test_makefoo_1 "NANAiiNAii" "n::NA, n::NA >" } # # Tests start here. # # 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 completion of a function that is defined in different scopes # with different parameters. proc_with_prefix overload-2 {} { with_test_prefix "all" { set completion_list { "(anonymous namespace)::overload2_function(overload2_arg3)" "(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg4)" "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)" "ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)" "ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)" "ns_overload2_test::(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg8)" "ns_overload2_test::overload2_function(overload2_arg5)" "ns_overload2_test::struct_overload2_test::overload2_function(overload2_arg6)" "overload2_function(overload2_arg1)" "struct_overload2_test::overload2_function(overload2_arg2)" } foreach cmd_prefix {"b" "b -function"} { test_gdb_complete_multiple \ "$cmd_prefix " "overload2_func" "tion(overload2_arg" $completion_list check_bp_locations_match_list \ "$cmd_prefix overload2_function" $completion_list } } # Same, but restrict to functions/methods in some scope. with_test_prefix "restrict scope" { set completion_list { "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)" "ns_overload2_test::overload2_function(overload2_arg5)" } foreach cmd_prefix {"b" "b -function"} { test_gdb_complete_multiple \ "$cmd_prefix " "ns_overload2_test::overload2_func" "tion(overload2_arg" $completion_list check_bp_locations_match_list \ "$cmd_prefix ns_overload2_test::overload2_function" $completion_list } } # Restrict to anonymous namespace scopes. with_test_prefix "restrict scope 2" { set completion_list { "(anonymous namespace)::overload2_function(overload2_arg3)" "ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)" } foreach cmd_prefix {"b" "b -function"} { test_gdb_complete_multiple \ "$cmd_prefix " "(anonymous namespace)::overload2_func" "tion(overload2_arg" $completion_list check_bp_locations_match_list \ "$cmd_prefix (anonymous namespace)::overload2_function" $completion_list } } # Add enough scopes, and we get a unique completion. with_test_prefix "unique completion" { foreach cmd_prefix {"b" "b -function"} { test_gdb_complete_unique \ "$cmd_prefix ns_overload2_test::(anonymous namespace)::overload2_func" \ "$cmd_prefix ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)" check_setting_bp_fails "$cmd_prefix ns_overload2_test::(anonymous namespace)::overload2_func" check_bp_locations_match_list \ "$cmd_prefix ns_overload2_test::(anonymous namespace)::overload2_function" \ {"ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"} } } } # Test linespecs / locations using fully-qualified names. proc_with_prefix fqn {} { # "-qualified" works with both explicit locations and linespecs. # Also test that combining a source file with a function name # still results in a full match, with both linespecs and explicit # locations. foreach cmd_prefix { "b -qualified " "b -qualified -function " "b -qualified cpls.cc:" "b -qualified -source cpls.cc -function " "b -source cpls.cc -qualified -function " } { test_gdb_complete_unique \ "${cmd_prefix}overload2_func" \ "${cmd_prefix}overload2_function(overload2_arg1)" # Drill down until we find a unique completion. test_gdb_complete_multiple "${cmd_prefix}" "ns_overload2_test::" "" { "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)" "ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)" "ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)" "ns_overload2_test::(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg8)" "ns_overload2_test::overload2_function(overload2_arg5)" "ns_overload2_test::struct_overload2_test::overload2_function(overload2_arg6)" } test_gdb_complete_multiple "${cmd_prefix}" "ns_overload2_test::(anonymous namespace)::" "" { "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)" "ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)" "ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)" "ns_overload2_test::(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg8)" } test_gdb_complete_multiple "${cmd_prefix}" "ns_overload2_test::(anonymous namespace)::ns_overload2_test::" "" { "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)" "ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)" } test_gdb_complete_unique \ "${cmd_prefix}ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_func" \ "${cmd_prefix}ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)" } } # Check that a fully-qualified lookup name doesn't match symbols in # nested scopes. proc_with_prefix fqn-2 {} { set linespec "struct_overload2_test::overload2_function(overload2_arg6)" set cmd_prefix "b -qualified" check_setting_bp_fails "$cmd_prefix $linespec" test_gdb_complete_none "$cmd_prefix $linespec" # Check that using the same name, but not fully-qualifying it, # would find something, just to make sure the test above is # testing what we intend to test. set cmd_prefix "b -function" test_gdb_complete_unique "$cmd_prefix $linespec" "$cmd_prefix $linespec" check_bp_locations_match_list \ "$cmd_prefix $linespec" \ {"ns_overload2_test::struct_overload2_test::overload2_function(overload2_arg6)"} } # Test completion of functions in different scopes that have the same # name and parameters. Restricting the scopes should find fewer and # fewer matches. proc_with_prefix overload-3 {} { with_test_prefix "all overloads" { set completion_list { "(anonymous namespace)::overload3_function(int)" "(anonymous namespace)::overload3_function(long)" "(anonymous namespace)::struct_overload3_test::overload3_function(int)" "(anonymous namespace)::struct_overload3_test::overload3_function(long)" "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(long)" "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(long)" "ns_overload3_test::(anonymous namespace)::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::overload3_function(long)" "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(long)" "ns_overload3_test::overload3_function(int)" "ns_overload3_test::overload3_function(long)" "ns_overload3_test::struct_overload3_test::overload3_function(int)" "ns_overload3_test::struct_overload3_test::overload3_function(long)" "overload3_function(int)" "overload3_function(long)" "struct_overload3_test::overload3_function(int)" "struct_overload3_test::overload3_function(long)" } foreach cmd_prefix {"b" "b -function"} { test_gdb_complete_multiple "$cmd_prefix " "overload3_func" "tion(" $completion_list check_bp_locations_match_list "$cmd_prefix overload3_function" $completion_list } } with_test_prefix "restrict overload" { foreach cmd_prefix {"b" "b -function"} { test_gdb_complete_unique \ "$cmd_prefix overload3_function(int)" \ "$cmd_prefix overload3_function(int)" check_bp_locations_match_list "$cmd_prefix overload3_function(int)" { "(anonymous namespace)::overload3_function(int)" "(anonymous namespace)::struct_overload3_test::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(int)" "ns_overload3_test::overload3_function(int)" "ns_overload3_test::struct_overload3_test::overload3_function(int)" "overload3_function(int)" "struct_overload3_test::overload3_function(int)" } } } with_test_prefix "restrict scope" { set completion_list { "(anonymous namespace)::struct_overload3_test::overload3_function(int)" "(anonymous namespace)::struct_overload3_test::overload3_function(long)" "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(long)" "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(long)" "ns_overload3_test::struct_overload3_test::overload3_function(int)" "ns_overload3_test::struct_overload3_test::overload3_function(long)" "struct_overload3_test::overload3_function(int)" "struct_overload3_test::overload3_function(long)" } foreach cmd_prefix {"b" "b -function"} { test_gdb_complete_multiple \ "$cmd_prefix " "struct_overload3_test::overload3_func" "tion(" \ $completion_list check_bp_locations_match_list \ "$cmd_prefix struct_overload3_test::overload3_function" \ $completion_list } } } # Test completing an overloaded template method. proc_with_prefix template-overload {} { set completion_list { "template_struct::template_overload_fn(int)" "template_struct::template_overload_fn(long)" } foreach cmd_prefix {"b" "b -function"} { test_gdb_complete_multiple "$cmd_prefix " "template_overload_fn" "(" $completion_list check_bp_locations_match_list "$cmd_prefix template_overload_fn" $completion_list check_bp_locations_match_list \ "$cmd_prefix template_struct::template_overload_fn" \ "template_struct::template_overload_fn(int)" } } # Test completing template methods with non-void return type. proc_with_prefix template-ret-type {} { set method_name "template2_fn" set param_list "(template2_ret_type, int, int)" set struct_type "template2_struct >" set ret_type "template2_ret_type" # Templates are listed both with and without return type, making # "template2_" ambiguous. foreach cmd_prefix {"b" "b -function"} { set completion_list \ [list \ "${ret_type} ${struct_type}::${method_name}${param_list}" \ "${struct_type}::${method_name}${param_list}"] test_gdb_complete_multiple "$cmd_prefix " "template2_" "" $completion_list # Add one character more after "2_", and the linespec becomes # unambiguous. Test completing the whole prefix range after that, # thus testing completing either with or without return type. foreach {s t} [list \ "template2_r" \ "${ret_type} ${struct_type}::${method_name}${param_list}" \ "template2_s" \ "${struct_type}::${method_name}${param_list}"] { set linespec $t set complete_line "$cmd_prefix $linespec" set start [index_after $s $complete_line] test_complete_prefix_range $complete_line $start } # Setting a breakpoint with or without template params and without # the method params works, just like with non-template functions. # It also works with or without return type. foreach linespec [list \ "template2_fn" \ "${method_name}" \ "${method_name}${param_list}" \ "${struct_type}::${method_name}" \ "${struct_type}::${method_name}${param_list}" \ "${ret_type} ${struct_type}::${method_name}" \ "${ret_type} ${struct_type}::${method_name}${param_list}"] { check_bp_locations_match_list \ "$cmd_prefix $linespec" \ [list "${struct_type}::${method_name}${param_list}"] } } } # Test completion of function template foo. proc_with_prefix template-function-foo {} { foreach cmd_prefix {"b" "b -function"} { # "foo" is ambiguous, this will set many different breakpoints. set completion_list \ [list \ [makefoo Aabiaai] \ [makefoo Aabiabi] \ [makefoo Aabicdi] \ [makefoo AabicdiAabiaai] \ [makefoo AabicdiAabiabi] \ [makefoo AabicdiBabicdi] \ [makefoo Babicdi] \ [makefoo aai] \ [makefoo aaiabi] \ [makefoo aaicci] \ [makefoo aaicdi] \ [makefoo abi] \ [makefoo anabnb] \ [makefoo cci] \ [makefoo cdi] \ [makefoo NAnanbNBnanb] \ [makefoo nanb]] test_gdb_complete_multiple "$cmd_prefix " "foo" "<" $completion_list check_bp_locations_match_list "$cmd_prefix foo" $completion_list # "foo<" should give the same result, but it should not set any # breakpoints. test_gdb_complete_multiple "$cmd_prefix " "foo<" "" $completion_list check_setting_bp_fails "$cmd_prefix foo<" # "foo >, " \ $completion_list check_setting_bp_fails "$cmd_prefix foo" should give any function with one parameter of any type # of A. While the parameter list in the template should be ignored, # the function's argument list should not be ignored. set completion_list \ [list \ [makefoo Aabiaai] \ [makefoo Aabiabi] \ [makefoo Aabicdi]] test_gdb_complete_multiple "$cmd_prefix " "foo" \ "(A >, " $completion_list check_bp_locations_match_list "$cmd_prefix foo" $completion_list # "foo, a" should give all completions starting with # "Aabia" but it is insufficient to set breakpoints. set completion_list \ [list \ [makefoo Aabiaai] \ [makefoo Aabiabi]] test_gdb_complete_multiple "$cmd_prefix " "foo >, a" \ "<" $completion_list check_setting_bp_fails "$cmd_prefix foo >, a" # "foo, a<" should yield the same results as above. test_gdb_complete_multiple "$cmd_prefix " "foo >, a<" \ "" $completion_list check_setting_bp_fails "$cmd_prefix foo >, a<" # "foo, a") test_gdb_complete_unique "$cmd_prefix foo >, a >, a, a"). test_gdb_complete_unique "$cmd_prefix foo >, a >, a" yields the same unique result and sets a breakpoint. # Since the input skips the parameter list, so does the completion. test_gdb_complete_unique "$cmd_prefix foo" \ "$cmd_prefix foo(B >, c > >)" check_bp_locations_match_list "$cmd_prefix foo" \ [list [makefoo Babicdi]] # "foo >" is unique and sets a breakpoint. # Multiple template parameter lists are skipped, so GDB will ignore # them in the completion. test_gdb_complete_unique "$cmd_prefix foo >" \ "$cmd_prefix foo >(A >, c > >)" check_bp_locations_match_list "$cmd_prefix foo >" \ [list [makefoo Aabicdi]] } } # Helper for template-class-with-method to build completion lists. proc makem {arglist_list} { set completion_list {} foreach arglist $arglist_list { lappend completion_list "[maketype $arglist]::method()" } return $completion_list } # Returns a list of elements that look like # void TYPE::method() # where TYPE is derived from each arglist in ARGLIST_LIST. proc test_makem_1 {arglist_list expected_list} { set result [makem $arglist_list] send_log "makem $arglist = $result\n" send_log "expecting $expected_list\n" # Do list equality via canonical strings. if {[expr {[list {*}$expected_list] eq [list {*}$result]}]} { pass "makem unit test: $arglist" } else { fail "makem unit test: $arglist" } } # Unit tests for makem. proc test_makem {} { test_makem_1 ai {"a::method()"} test_makem_1 bi {"b::method()"} test_makem_1 {ai bi} {"a::method()" "b::method()"} test_makem_1 {Aaiaai Bbibbi abi cdi} { "A, a > >::method()" "B, b > >::method()" "a >::method()" "c >::method()" } } # Test class template containing a (non-templated) method called "method." proc_with_prefix template-class-with-method {} { foreach {type type_list} \ [list \ "" {aai abi cci cdi Aabicdi Aabiaai Aabiabi Babicdi} \ "a" {aai abi} \ "b" {} \ "c" {cci cdi} \ "A" {Aabicdi Aabiaai Aabiabi} \ "B" {Babicdi} \ "A" {Aabiaai Aabiabi} \ "A, c>" {Aabicdi}\ "A" {} \ "B" {} \ "B" {} \ "B" {Babicdi}] \ { foreach cmd_prefix {"b" "b -function"} { set c "$cmd_prefix " if {$type != ""} { append c "${type}::" } append c "method" if {[llength $type_list] > 0} { test_gdb_complete_unique $c "${c}()" check_bp_locations_match_list $c [makem $type_list] } else { test_gdb_complete_none $c } } } } # Test completion of a const-overloaded funtion (const-overload). # Note that "const" appears after the function/method parameters. proc_with_prefix const-overload {} { set completion_list { "struct_with_const_overload::const_overload_fn()" "struct_with_const_overload::const_overload_fn() const" } foreach cmd_prefix {"b" "b -function"} { test_gdb_complete_multiple \ "$cmd_prefix " "const_overload_fn" "()" \ $completion_list test_gdb_complete_multiple \ "$cmd_prefix " "const_overload_fn ( " ")" \ $completion_list test_gdb_complete_multiple \ "$cmd_prefix " "const_overload_fn()" "" \ $completion_list check_bp_locations_match_list \ "$cmd_prefix const_overload_fn" \ {"struct_with_const_overload::const_overload_fn()" "struct_with_const_overload::const_overload_fn() const"} check_setting_bp_fails "$cmd_prefix const_overload_fn(" check_bp_locations_match_list \ "$cmd_prefix const_overload_fn()" \ {"struct_with_const_overload::const_overload_fn()"} check_bp_locations_match_list \ "$cmd_prefix const_overload_fn() const" \ {"struct_with_const_overload::const_overload_fn() const"} } } # Same but quote-enclose the function name. This makes the overload # no longer be ambiguous. proc_with_prefix const-overload-quoted {} { foreach cmd_prefix {"b" "b -function"} { set linespec "'const_overload_fn()'" test_gdb_complete_unique "$cmd_prefix $linespec" "$cmd_prefix $linespec" check_bp_locations_match_list \ "$cmd_prefix $linespec" { "struct_with_const_overload::const_overload_fn()" } set linespec "'const_overload_fn() const'" test_gdb_complete_unique "$cmd_prefix $linespec" "$cmd_prefix $linespec" check_bp_locations_match_list \ "$cmd_prefix $linespec" { "struct_with_const_overload::const_overload_fn() const" } } } # Test that when the function is unambiguous, linespec completion # appends the end quote char automatically, both ' and ". proc_with_prefix append-end-quote-char-when-unambiguous {} { 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 } } # Test completing functions/methods in anonymous namespaces. proc_with_prefix anon-ns {} { foreach cmd_prefix {"b" "b -function"} { foreach qc $completion::maybe_quoted_list { test_gdb_complete_unique \ "$cmd_prefix ${qc}anon_ns_function" \ "$cmd_prefix ${qc}anon_ns_function()${qc}" check_bp_locations_match_list "$cmd_prefix ${qc}anon_ns_function()${qc}" { "(anonymous namespace)::anon_ns_function()" "(anonymous namespace)::anon_ns_struct::anon_ns_function()" "the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_function()" "the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_struct::anon_ns_function()" } } # A "(" finds all anonymous namespace functions/methods in all # scopes. test_gdb_complete_multiple "$cmd_prefix " "(" "anonymous namespace)::" { "(anonymous namespace)::anon_ns_function()" "(anonymous namespace)::anon_ns_struct::anon_ns_function()" "(anonymous namespace)::overload2_function(overload2_arg3)" "(anonymous namespace)::overload3_function(int)" "(anonymous namespace)::overload3_function(long)" "(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg4)" "(anonymous namespace)::struct_overload3_test::overload3_function(int)" "(anonymous namespace)::struct_overload3_test::overload3_function(long)" "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)" "ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)" "ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)" "ns_overload2_test::(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg8)" "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(long)" "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(long)" "ns_overload3_test::(anonymous namespace)::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::overload3_function(long)" "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(int)" "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(long)" "the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_function()" "the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_struct::anon_ns_function()" } set function "the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_function()" test_gdb_complete_unique "$cmd_prefix $function" "$cmd_prefix $function" check_bp_locations_match_list "$cmd_prefix $function" [list $function] # Test completing after the "(anonymous namespace)" part. test_gdb_complete_unique \ "$cmd_prefix the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_fu" \ "$cmd_prefix $function" # Test whitespace in the "(anonymous namespace)" component. test_gdb_complete_unique \ "$cmd_prefix the_anon_ns_wrapper_ns::( anonymous namespace )::anon_ns_fu" \ "$cmd_prefix the_anon_ns_wrapper_ns::( anonymous namespace )::anon_ns_function()" check_setting_bp_fails \ "$cmd_prefix the_anon_ns_wrapper_ns::( anonymous namespace )::anon_ns_fu" set function_ws \ "the_anon_ns_wrapper_ns::( anonymous namespace )::anon_ns_function ( )" test_gdb_complete_unique "$cmd_prefix $function_ws" "$cmd_prefix $function_ws" check_bp_locations_match_list "$cmd_prefix $function_ws" [list $function] } } # Basic test for completing "operator<". More extensive C++ operator # tests in cpls-op.exp. proc_with_prefix operator< {} { # Complete all prefixes between "oper" and the whole prototype. set function "operator<(foo_enum, foo_enum)" foreach cmd_prefix {"b" "b -function"} { set line "$cmd_prefix $function" set start [index_after "oper" $line] test_complete_prefix_range $line $start } # There's a label in the function; try completing it. (Exhaustive # label completion tests further below.) foreach location [list \ "$function:label1" \ "-function $function -label label1"] { set cmd "b $location" set input_line [string range $cmd 0 [expr [string length $cmd] - 3]] test_gdb_complete_unique $input_line $cmd test_gdb_complete_unique $cmd $cmd check_bp_locations_match_list $cmd [list "$location"] } } # Test completion of scopes with an ambiguous prefix. proc_with_prefix ambiguous-prefix {} { foreach cmd_prefix {"b" "b -function"} { test_gdb_complete_multiple "$cmd_prefix " "ambiguous_pre" "fix_" { "ambiguous_prefix_global_func()" "the_ambiguous_prefix_ns::ambiguous_prefix_ns_func()" "the_ambiguous_prefix_struct::ambiguous_prefix_method()" } check_setting_bp_fails "$cmd_prefix ambiguous_prefix_" } } # Test completion of function labels. proc_with_prefix function-labels {} { # Test with and without a source file component. foreach_location_functions \ { "" "cpls.cc" } \ { "function_with_labels(int)" } \ { # Linespec version. Test various spacing around the label # colon separator. foreach label_sep {":" " :" ": " " : "} { set linespec "${location}${label_sep}" test_gdb_complete_multiple "b $linespec" "l" "abel" { "label1" "label2" } check_setting_bp_fails "b ${linespec}label" set tsep [string trim ${source_sep}] check_bp_locations_match_list \ "b ${linespec}label1" [list "${source}${tsep}${function}:label1"] check_bp_locations_match_list \ "b ${linespec}label2" [list "${source}${tsep}${function}:label2"] } } \ { # Explicit locations version. append location " -label" test_gdb_complete_multiple "b $location " "l" "abel" { "label1" "label2" } check_setting_bp_fails "b $location label" if {$source != ""} { set bp_loc_src "-source ${source} " } else { set bp_loc_src "" } check_bp_locations_match_list \ "b ${location} label1" [list "${bp_loc_src}-function $function -label label1"] check_bp_locations_match_list \ "b ${location} label2" [list "${bp_loc_src}-function $function -label label2"] } } # Test that completion after a function name offers keyword # (if/task/thread/-force-condition) matches in linespec mode, and also # the explicit location options in explicit locations mode. proc_with_prefix keywords-after-function {} { set explicit_list \ [lsort [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 \ [lsort [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 overload-2 fqn fqn-2 overload-3 template-overload template-ret-type #test_makefoo template-function-foo #test_makem template-class-with-method const-overload const-overload-quoted append-end-quote-char-when-unambiguous in-source-file-unconstrained in-source-file-unambiguous in-source-file-ambiguous source-complete-appends-colon incomplete-scope-colon anon-ns operator< ambiguous-prefix function-labels keywords-after-function keywords-after-label keywords-after-unknown-file no-data-symbols if-expression } test_driver