Enhance the menu to select function overloads with signatures
authorPierre-Marie de Rodat <derodat@adacore.com>
Thu, 3 Sep 2015 15:34:58 +0000 (17:34 +0200)
committerPierre-Marie de Rodat <derodat@adacore.com>
Mon, 7 Dec 2015 12:32:43 +0000 (13:32 +0100)
So far, trying to evaluate an expression involving a function call for
which GDB could find multiple function candidates outputs a menu so that
the user can select the one to run.  For instance, with the two
following functions:

    type New_Integer is new Integer;

    function F (I : Integer) return Boolean;
    function F (I : New_Integer) return Boolean;

Then we get the following GDB session:

    (gdb) print f(1)
    Multiple matches for f
    [0] cancel
    [1] foo.f at foo.adb:23
    [2] foo.f at foo.adb.28
    >

While the source location information is sufficient in order to
determine which one to select, one has to look for them in source files,
which is not convenient.

This commit tunes this menu in order to also include the list of formal
and return types (if any) in each entry.  The above then becomes:

    (gdb) print f(1)
    Multiple matches for f
    [0] cancel
    [1] foo.f (integer) return boolean at foo.adb:23
    [2] foo.f (foo.new_integer) return boolean at foo.adb.28
    >

Since this output is more verbose than previously, this change also
introduces an option (set/show ada print-signatures) to get the original
output.

gdb/ChangeLog:

* ada-lang.c (print_signatures): New.
(ada_print_symbol_signature): New.
(user_select_syms): Add signatures to the output of candidate
symbols using ada_print_symbol_signature.
(_initialize_ada_language): Add a "set/show ada
print-signatures" boolean option.

gdb/testsuite/ChangeLog:

* gdb.ada/fun_overload_menu.exp: New testcase.
* gdb.ada/fun_overload_menu/foo.adb: New testcase.

Tested on x86_64-linux, no regression.

gdb/ChangeLog
gdb/ada-lang.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.ada/fun_overload_menu.exp [new file with mode: 0644]
gdb/testsuite/gdb.ada/fun_overload_menu/foo.adb [new file with mode: 0644]

index de343d8e90487c91a2d80cbd3cd58cb3455f7b6a..f3537ea50e443ffdbd30c4a9a620385c10ef4968 100644 (file)
@@ -1,3 +1,12 @@
+2015-12-07  Pierre-Marie de Rodat  <derodat@adacore.com>
+
+       * ada-lang.c (print_signatures): New.
+       (ada_print_symbol_signature): New.
+       (user_select_syms): Add signatures to the output of candidate
+       symbols using ada_print_symbol_signature.
+       (_initialize_ada_language): Add a "set/show ada
+       print-signatures" boolean option.
+
 2015-12-07  Andreas Arnez <arnez@linux.vnet.ibm.com>
 
        * MAINTAINERS (Write After Approval): Add Andreas Arnez.
index 1f2d014ce9e3a5ad35f623792a65d2c463acbace..3fe7f9a77a6a186819d8de979fd1e457cf51bc10 100644 (file)
@@ -3822,6 +3822,49 @@ sort_choices (struct block_symbol syms[], int nsyms)
     }
 }
 
+/* Whether GDB should display formals and return types for functions in the
+   overloads selection menu.  */
+static int print_signatures = 1;
+
+/* Print the signature for SYM on STREAM according to the FLAGS options.  For
+   all but functions, the signature is just the name of the symbol.  For
+   functions, this is the name of the function, the list of types for formals
+   and the return type (if any).  */
+
+static void
+ada_print_symbol_signature (struct ui_file *stream, struct symbol *sym,
+                           const struct type_print_options *flags)
+{
+  struct type *type = SYMBOL_TYPE (sym);
+
+  fprintf_filtered (stream, "%s", SYMBOL_PRINT_NAME (sym));
+  if (!print_signatures
+      || type == NULL
+      || TYPE_CODE (type) != TYPE_CODE_FUNC)
+    return;
+
+  if (TYPE_NFIELDS (type) > 0)
+    {
+      int i;
+
+      fprintf_filtered (stream, " (");
+      for (i = 0; i < TYPE_NFIELDS (type); ++i)
+       {
+         if (i > 0)
+           fprintf_filtered (stream, "; ");
+         ada_print_type (TYPE_FIELD_TYPE (type, i), NULL, stream, -1, 0,
+                         flags);
+       }
+      fprintf_filtered (stream, ")");
+    }
+  if (TYPE_TARGET_TYPE (type) != NULL
+      && TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
+    {
+      fprintf_filtered (stream, " return ");
+      ada_print_type (TYPE_TARGET_TYPE (type), NULL, stream, -1, 0, flags);
+    }
+}
+
 /* Given a list of NSYMS symbols in SYMS, select up to MAX_RESULTS>0 
    by asking the user (if necessary), returning the number selected, 
    and setting the first elements of SYMS items.  Error if no symbols
@@ -3871,14 +3914,14 @@ See set/show multiple-symbol."));
           struct symtab_and_line sal =
             find_function_start_sal (syms[i].symbol, 1);
 
+         printf_unfiltered ("[%d] ", i + first_choice);
+         ada_print_symbol_signature (gdb_stdout, syms[i].symbol,
+                                     &type_print_raw_options);
          if (sal.symtab == NULL)
-           printf_unfiltered (_("[%d] %s at <no source file available>:%d\n"),
-                              i + first_choice,
-                              SYMBOL_PRINT_NAME (syms[i].symbol),
+           printf_unfiltered (_(" at <no source file available>:%d\n"),
                               sal.line);
          else
-           printf_unfiltered (_("[%d] %s at %s:%d\n"), i + first_choice,
-                              SYMBOL_PRINT_NAME (syms[i].symbol),
+           printf_unfiltered (_(" at %s:%d\n"),
                               symtab_to_filename_for_display (sal.symtab),
                               sal.line);
           continue;
@@ -3895,11 +3938,14 @@ See set/show multiple-symbol."));
            symtab = symbol_symtab (syms[i].symbol);
 
           if (SYMBOL_LINE (syms[i].symbol) != 0 && symtab != NULL)
-            printf_unfiltered (_("[%d] %s at %s:%d\n"),
-                               i + first_choice,
-                               SYMBOL_PRINT_NAME (syms[i].symbol),
-                              symtab_to_filename_for_display (symtab),
-                              SYMBOL_LINE (syms[i].symbol));
+           {
+             printf_unfiltered ("[%d] ", i + first_choice);
+             ada_print_symbol_signature (gdb_stdout, syms[i].symbol,
+                                         &type_print_raw_options);
+             printf_unfiltered (_(" at %s:%d\n"),
+                                symtab_to_filename_for_display (symtab),
+                                SYMBOL_LINE (syms[i].symbol));
+           }
           else if (is_enumeral
                    && TYPE_NAME (SYMBOL_TYPE (syms[i].symbol)) != NULL)
             {
@@ -3909,19 +3955,22 @@ See set/show multiple-symbol."));
               printf_unfiltered (_("'(%s) (enumeral)\n"),
                                  SYMBOL_PRINT_NAME (syms[i].symbol));
             }
-          else if (symtab != NULL)
-            printf_unfiltered (is_enumeral
-                               ? _("[%d] %s in %s (enumeral)\n")
-                               : _("[%d] %s at %s:?\n"),
-                               i + first_choice,
-                               SYMBOL_PRINT_NAME (syms[i].symbol),
-                               symtab_to_filename_for_display (symtab));
-          else
-            printf_unfiltered (is_enumeral
-                               ? _("[%d] %s (enumeral)\n")
-                               : _("[%d] %s at ?\n"),
-                               i + first_choice,
-                               SYMBOL_PRINT_NAME (syms[i].symbol));
+         else
+           {
+             printf_unfiltered ("[%d] ", i + first_choice);
+             ada_print_symbol_signature (gdb_stdout, syms[i].symbol,
+                                         &type_print_raw_options);
+
+             if (symtab != NULL)
+               printf_unfiltered (is_enumeral
+                                  ? _(" in %s (enumeral)\n")
+                                  : _(" at %s:?\n"),
+                                  symtab_to_filename_for_display (symtab));
+             else
+               printf_unfiltered (is_enumeral
+                                  ? _(" (enumeral)\n")
+                                  : _(" at ?\n"));
+           }
         }
     }
 
@@ -14136,6 +14185,14 @@ this incurs a slight performance penalty, so it is recommended to NOT change\n\
 this option to \"off\" unless necessary."),
                             NULL, NULL, &set_ada_list, &show_ada_list);
 
+  add_setshow_boolean_cmd ("print-signatures", class_vars,
+                          &print_signatures, _("\
+Enable or disable the output of formal and return types for functions in the \
+overloads selection menu"), _("\
+Show whether the output of formal and return types for functions in the \
+overloads selection menu is activated"),
+                          NULL, NULL, NULL, &set_ada_list, &show_ada_list);
+
   add_catch_command ("exception", _("\
 Catch Ada exceptions, when raised.\n\
 With an argument, catch only exceptions with the given name."),
index 99bfed8ab2308415fe6de77b0423f90c9c6c826f..8316d32773f8c731004ca84cf73ba34b9abcac69 100644 (file)
@@ -1,3 +1,8 @@
+2015-12-07  Pierre-Marie de Rodat  <derodat@adacore.com>
+
+       * gdb.ada/fun_overload_menu.exp: New testcase.
+       * gdb.ada/fun_overload_menu/foo.adb: New testcase.
+
 2015-12-04  Josh Stone  <jistone@redhat.com>
 
        * gdb.base/catch-fork-static.exp: New.
diff --git a/gdb/testsuite/gdb.ada/fun_overload_menu.exp b/gdb/testsuite/gdb.ada/fun_overload_menu.exp
new file mode 100644 (file)
index 0000000..5a1c37a
--- /dev/null
@@ -0,0 +1,71 @@
+# Copyright 2015 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/>.
+
+load_lib "ada.exp"
+
+standard_ada_testfile foo
+
+if {[gdb_compile_ada "$srcfile" "$binfile" executable [list debug]] != "" } {
+  return -1
+}
+
+clean_restart ${testfile}
+
+set bp_location [gdb_get_line_number "BREAK" ${testdir}/foo.adb]
+runto "foo.adb:$bp_location"
+
+
+proc test_menu {expr function menu_entries selection output} {
+    set menu [multi_line "Multiple matches for $function" \
+                         "\\\[0\\\] cancel" \
+                         "$menu_entries" \
+                         "> $"]
+    set test_name "multiple matches for $function ($expr)"
+    gdb_test_multiple "print $expr" "$test_name" \
+    {
+        -re "$menu" {
+            pass "$test_name"
+        }
+        default {
+            fail "$test_name"
+        }
+    }
+    gdb_test "$selection" "$output"
+}
+
+
+# Check that function signatures in overload menus are displayed as expected.
+
+# 1. Test with overloaded functions
+test_menu "f (1, null)" "f" \
+          [multi_line \
+           "\\\[1\\\] foo\.f \\(integer; foo\.integer_access\\) return boolean at .*foo.adb:.*" \
+           "\\\[2\\\] foo\.f \\(foo\.new_integer; foo\.integer_access\\) return boolean at .*foo.adb:.*"] \
+          "1" "= true"
+
+# 2. Test with overloaded procedures
+test_menu "p (1, null)" "p" \
+          [multi_line \
+           "\\\[1\\\] foo\.p \\(integer; foo\.integer_access\\) at .*foo.adb:.*" \
+           "\\\[2\\\] foo\.p \\(foo\.new_integer; foo\.integer_access\\) at .*foo.adb:.*" ] \
+          "1" "= (void)"
+
+# 3. Test with signatures disabled
+gdb_test "set ada print-signatures off" ""
+test_menu "f (1, null)" "f" \
+          [multi_line \
+           "\\\[1\\\] foo\.f at .*foo.adb:.*" \
+           "\\\[2\\\] foo\.f at .*foo.adb:.*"] \
+          "1" "= true"
diff --git a/gdb/testsuite/gdb.ada/fun_overload_menu/foo.adb b/gdb/testsuite/gdb.ada/fun_overload_menu/foo.adb
new file mode 100644 (file)
index 0000000..75009ae
--- /dev/null
@@ -0,0 +1,47 @@
+--  Copyright 2015 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/>.
+
+procedure Foo is
+
+   type New_Integer is new Integer;
+   type Integer_Access is access Integer;
+
+   function F (I : Integer; A : Integer_Access) return Boolean is
+   begin
+      return True;
+   end F;
+
+   function F (I : New_Integer; A : Integer_Access) return Boolean is
+   begin
+      return False;
+   end F;
+
+   procedure P (I : Integer; A : Integer_Access) is
+   begin
+      null;
+   end P;
+
+   procedure P (I : New_Integer; A : Integer_Access) is
+   begin
+      null;
+   end P;
+
+   B1 : constant Boolean := F (Integer'(1), null); --  BREAK
+   B2 : constant Boolean := F (New_Integer'(2), null);
+
+begin
+   P (Integer'(3), null);
+   P (New_Integer'(4), null);
+end Foo;