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


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

RFA: PR 2484: completion of macro names


This patch fixes PR gdb/2484.  The bug here is that TAB completion
does not complete macro names.

This patch adds a new la_macro_expansion field to struct
language_defn, and updates all the languages.  (It also fixes a bug in
field ordering in a couple language initializers.)

It also adds a callback argument to macro_for_each.

In keeping with my understanding of Jim's wishes for the macro code, I
made the new macro_for_each_in_scope take an explicit pair of
file/line arguments, rather than a macro_scope.  This means that
macrotab.c still can remain blissfully ignorant of struct macro_scope.

The guts of the change are in symtab.c.  The patch changes
default_make_symbol_completion_list to look at all the macros in scope,
plus all the user-defined macros.

Built and regression tested on the compile farm (x86-64).
A couple new test cases included.

Ok?

Tom

2008-07-28  Tom Tromey  <tromey@redhat.com>

	PR gdb/2484:
	* symtab.c (struct add_macro_name_data): New struct.
	(add_macro_name): New function.
	(default_make_symbol_completion_list): Complete macro names.
	* scm-lang.c (scm_language_defn): Update.
	* p-lang.c (pascal_language_defn): Update.
	* objc-lang.c (objc_language_defn): Update.
	* macrotab.h (struct macro_scope): Declare.
	(macro_callback_fn): Add user_data argument.
	(macro_for_each): Likewise.
	(macro_for_each_in_scope): Declare.
	* macrotab.c: (struct macro_for_each_data): New struct.
	(foreach_macro): Use it.
	(macro_for_each): Likewise.
	(foreach_macro_in_scope): New function.
	(macro_for_each_in_scope): Likewise.
	* macrocmd.c (print_one_macro): Add argument.
	(macro_list_command): Pass NULL to macro_for_each.
	* m2-lang.c (m2_language_defn): Update.
	* language.h (struct language_defn) <la_macro_expansion>: New
	field.
	* language.c (unknown_language_defn): Update.  Fix order of
	initializers.
	(auto_language_defn): Likewise.
	(local_language_defn): Update.
	* jv-lang.c (java_language_defn): Update.
	* f-lang.c (f_language_defn): Update.
	* c-lang.c (c_language_defn): Update.
	(cplus_language_defn): Likewise.
	(asm_language_defn): Likewise.
	(minimal_language_defn): Likewise.
	* ada-lang.c (ada_language_defn): Update.
	* Makefile.in (symtab.o): Add macroscope_h, macrotab_h.

b/gdb/testsuite/ChangeLog:
2008-07-28  Tom Tromey  <tromey@redhat.com>

	* gdb.base/macscp1.c (FIFTY_SEVEN): New macro.
	(TWENTY_THREE): Likewise.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index a24e29b..295455f 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -2904,7 +2904,7 @@ symtab.o: symtab.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(gdbcore_h) \
 	$(filenames_h) $(objc_lang_h) $(ada_lang_h) $(hashtab_h) \
 	$(gdb_obstack_h) $(block_h) $(dictionary_h) $(gdb_string_h) \
 	$(gdb_stat_h) $(cp_abi_h) $(observer_h) $(gdb_assert_h) \
-	$(solist_h) $(p_lang_h) $(addrmap_h)
+	$(solist_h) $(p_lang_h) $(addrmap_h) $(macrotab_h) $(macroscope_h)
 target.o: target.c $(defs_h) $(gdb_string_h) $(target_h) $(gdbcmd_h) \
 	$(symtab_h) $(inferior_h) $(bfd_h) $(symfile_h) $(objfiles_h) \
 	$(gdb_wait_h) $(dcache_h) $(regcache_h) $(gdb_assert_h) $(gdbcore_h) \
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index f3f1f34..5aabcdd 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10934,6 +10934,7 @@ const struct language_defn ada_language_defn = {
   case_sensitive_on,            /* Yes, Ada is case-insensitive, but
                                    that's not quite what this means.  */
   array_row_major,
+  0,
   &ada_exp_descriptor,
   parse,
   ada_error,
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 9ce4bb9..d467587 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -390,6 +390,7 @@ const struct language_defn c_language_defn =
   type_check_off,
   case_sensitive_on,
   array_row_major,
+  1,
   &exp_descriptor_standard,
   c_preprocess_and_parse,
   c_error,
@@ -503,6 +504,7 @@ const struct language_defn cplus_language_defn =
   type_check_off,
   case_sensitive_on,
   array_row_major,
+  1,
   &exp_descriptor_standard,
   c_preprocess_and_parse,
   c_error,
@@ -538,6 +540,7 @@ const struct language_defn asm_language_defn =
   type_check_off,
   case_sensitive_on,
   array_row_major,
+  1,
   &exp_descriptor_standard,
   c_preprocess_and_parse,
   c_error,
@@ -578,6 +581,7 @@ const struct language_defn minimal_language_defn =
   type_check_off,
   case_sensitive_on,
   array_row_major,
+  1,
   &exp_descriptor_standard,
   c_preprocess_and_parse,
   c_error,
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 5dcbd33..813cef7 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -313,6 +313,7 @@ const struct language_defn f_language_defn =
   type_check_on,
   case_sensitive_off,
   array_column_major,
+  0,
   &exp_descriptor_standard,
   f_parse,			/* parser */
   f_error,			/* parser error function */
diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c
index 6080839..4686c7b 100644
--- a/gdb/jv-lang.c
+++ b/gdb/jv-lang.c
@@ -1057,6 +1057,7 @@ const struct language_defn java_language_defn =
   type_check_off,
   case_sensitive_on,
   array_row_major,
+  0,
   &exp_descriptor_java,
   java_parse,
   java_error,
diff --git a/gdb/language.c b/gdb/language.c
index 66e5542..b5c8173 100644
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -1179,8 +1179,9 @@ const struct language_defn unknown_language_defn =
   language_unknown,
   range_check_off,
   type_check_off,
-  array_row_major,
   case_sensitive_on,
+  array_row_major,
+  0,
   &exp_descriptor_standard,
   unk_lang_parser,
   unk_lang_error,
@@ -1215,8 +1216,9 @@ const struct language_defn auto_language_defn =
   language_auto,
   range_check_off,
   type_check_off,
-  array_row_major,
   case_sensitive_on,
+  array_row_major,
+  0,
   &exp_descriptor_standard,
   unk_lang_parser,
   unk_lang_error,
@@ -1252,6 +1254,7 @@ const struct language_defn local_language_defn =
   type_check_off,
   case_sensitive_on,
   array_row_major,
+  0,
   &exp_descriptor_standard,
   unk_lang_parser,
   unk_lang_error,
diff --git a/gdb/language.h b/gdb/language.h
index 8bdc212..efea145 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -153,6 +153,9 @@ struct language_defn
     /* Multi-dimensional array ordering */
     enum array_ordering la_array_ordering;
 
+    /* True if this language supports C-like macro expansion.  */
+    unsigned int la_macro_expansion : 1;
+
     /* Definitions related to expression printing, prefixifying, and
        dumping */
 
diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index bb205ad..5e7c111 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -364,6 +364,7 @@ const struct language_defn m2_language_defn =
   type_check_on,
   case_sensitive_on,
   array_row_major,
+  0,
   &exp_descriptor_modula2,
   m2_parse,			/* parser */
   m2_error,			/* parser error function */
diff --git a/gdb/macrocmd.c b/gdb/macrocmd.c
index 4a70d4f..030251a 100644
--- a/gdb/macrocmd.c
+++ b/gdb/macrocmd.c
@@ -318,7 +318,8 @@ macro_undef_command (char *exp, int from_tty)
 
 
 static void
-print_one_macro (const char *name, const struct macro_definition *macro)
+print_one_macro (const char *name, const struct macro_definition *macro,
+		 void *ignore)
 {
   fprintf_filtered (gdb_stdout, "macro define %s", name);
   if (macro->kind == macro_function_like)
@@ -339,7 +340,7 @@ print_one_macro (const char *name, const struct macro_definition *macro)
 static void
 macro_list_command (char *exp, int from_tty)
 {
-  macro_for_each (macro_user_macros, print_one_macro);
+  macro_for_each (macro_user_macros, print_one_macro, NULL);
 }
 
 
diff --git a/gdb/macrotab.c b/gdb/macrotab.c
index 7633c98..a96d4af 100644
--- a/gdb/macrotab.c
+++ b/gdb/macrotab.c
@@ -887,25 +887,66 @@ macro_definition_location (struct macro_source_file *source,
 }
 
 
+/* The type for callback data for iterating the splay tree in
+   macro_for_each and macro_for_each_in_scope.  Only the latter uses
+   the FILE and LINE fields.  */
+struct macro_for_each_data
+{
+  macro_callback_fn fn;
+  void *user_data;
+  struct macro_source_file *file;
+  int line;
+};
+
 /* Helper function for macro_for_each.  */
 static int
-foreach_macro (splay_tree_node node, void *fnp)
+foreach_macro (splay_tree_node node, void *arg)
 {
-  macro_callback_fn *fn = (macro_callback_fn *) fnp;
+  struct macro_for_each_data *datum = (struct macro_for_each_data *) arg;
   struct macro_key *key = (struct macro_key *) node->key;
   struct macro_definition *def = (struct macro_definition *) node->value;
-  (**fn) (key->name, def);
+  (*datum->fn) (key->name, def, datum->user_data);
   return 0;
 }
 
 /* Call FN for every macro in TABLE.  */
 void
-macro_for_each (struct macro_table *table, macro_callback_fn fn)
+macro_for_each (struct macro_table *table, macro_callback_fn fn,
+		void *user_data)
+{
+  struct macro_for_each_data datum;
+  datum.fn = fn;
+  datum.user_data = user_data;
+  datum.file = NULL;
+  datum.line = 0;
+  splay_tree_foreach (table->definitions, foreach_macro, &datum);
+}
+
+static int
+foreach_macro_in_scope (splay_tree_node node, void *info)
 {
-  /* Note that we pass in the address of 'fn' because, pedantically
-     speaking, we can't necessarily cast a pointer-to-function to a
-     void*.  */
-  splay_tree_foreach (table->definitions, foreach_macro, &fn);
+  struct macro_for_each_data *datum = (struct macro_for_each_data *) info;
+  struct macro_key *key = (struct macro_key *) node->key;
+  struct macro_definition *def = (struct macro_definition *) node->value;
+
+  if (compare_locations (key->start_file, key->start_line,
+			 datum->file, datum->line) < 0)
+    (*datum->fn) (key->name, def, datum->user_data);
+  return 0;
+}
+
+/* Call FN for every macro is visible in SCOPE.  */
+void
+macro_for_each_in_scope (struct macro_source_file *file, int line,
+			 macro_callback_fn fn, void *user_data)
+{
+  struct macro_for_each_data datum;
+  datum.fn = fn;
+  datum.user_data = user_data;
+  datum.file = file;
+  datum.line = line;
+  splay_tree_foreach (file->table->definitions,
+		      foreach_macro_in_scope, &datum);
 }
 
 
diff --git a/gdb/macrotab.h b/gdb/macrotab.h
index 5ff36ea..25a6b88 100644
--- a/gdb/macrotab.h
+++ b/gdb/macrotab.h
@@ -75,6 +75,9 @@ struct macro_table;
 /* The definition of a single macro.  */
 struct macro_definition;
 
+/* A macro scope.  */
+struct macro_scope;
+
 /* A source file that participated in a compilation unit --- either a
    main file, or an #included file.  If a file is #included more than
    once, the presence of the `included_from' and `included_at_line'
@@ -305,12 +308,24 @@ struct macro_source_file *(macro_definition_location
                             int *definition_line));
 
 /* Callback function when walking a macro table.  NAME is the name of
-   the macro, and DEFINITION is the definition.  */
+   the macro, and DEFINITION is the definition.  USER_DATA is an
+   arbitrary pointer which is passed by the caller to macro_for_each
+   or macro_for_each_in_scope.  */
 typedef void (*macro_callback_fn) (const char *name,
-				   const struct macro_definition *definition);
-
-/* Call the function FN for each macro in the macro table TABLE.  */
-void macro_for_each (struct macro_table *table, macro_callback_fn fn);
+				   const struct macro_definition *definition,
+				   void *user_data);
+
+/* Call the function FN for each macro in the macro table TABLE.
+   USER_DATA is passed, untranslated, to FN.  */
+void macro_for_each (struct macro_table *table, macro_callback_fn fn,
+		     void *user_data);
+
+/* Call the function FN for each macro that is visible in a given
+   scope.  The scope is represented by FILE and LINE.  USER_DATA is
+   passed, untranslated, to FN.  */
+void macro_for_each_in_scope (struct macro_source_file *file, int line,
+			      macro_callback_fn fn,
+			      void *user_data);
 
 
 #endif /* MACROTAB_H */
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 56871e3..4ac1d33 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -497,6 +497,7 @@ const struct language_defn objc_language_defn = {
   type_check_off,
   case_sensitive_on,
   array_row_major,
+  1,
   &exp_descriptor_standard,
   objc_parse,
   objc_error,
diff --git a/gdb/p-lang.c b/gdb/p-lang.c
index 2accf35..e9329f1 100644
--- a/gdb/p-lang.c
+++ b/gdb/p-lang.c
@@ -403,6 +403,7 @@ const struct language_defn pascal_language_defn =
   type_check_on,
   case_sensitive_on,
   array_row_major,
+  0,
   &exp_descriptor_standard,
   pascal_parse,
   pascal_error,
diff --git a/gdb/scm-lang.c b/gdb/scm-lang.c
index 991e4b4..0020a57 100644
--- a/gdb/scm-lang.c
+++ b/gdb/scm-lang.c
@@ -240,6 +240,7 @@ const struct language_defn scm_language_defn =
   type_check_off,
   case_sensitive_off,
   array_row_major,
+  0,
   &exp_descriptor_scm,
   scm_parse,
   c_error,
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 2ab520d..2ea1a96 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -58,6 +58,8 @@
 #include "observer.h"
 #include "gdb_assert.h"
 #include "solist.h"
+#include "macrotab.h"
+#include "macroscope.h"
 
 /* Prototypes for local functions */
 
@@ -3636,6 +3638,29 @@ language_search_unquoted_string (char *text, char *p)
   return p;
 }
 
+/* Type of the user_data argument passed to add_macro_name.  The
+   contents are simply whatever is needed by
+   completion_list_add_name.  */
+struct add_macro_name_data
+{
+  char *sym_text;
+  int sym_text_len;
+  char *text;
+  char *word;
+};
+
+/* A callback used with macro_for_each and macro_for_each_in_scope.
+   This adds a macro's name to the current completion list.  */
+static void
+add_macro_name (const char *name, const struct macro_definition *ignore,
+		void *user_data)
+{
+  struct add_macro_name_data *datum = (struct add_macro_name_data *) user_data;
+  completion_list_add_name ((char *) name,
+			    datum->sym_text, datum->sym_text_len,
+			    datum->text, datum->word);
+}
+
 char **
 default_make_symbol_completion_list (char *text, char *word)
 {
@@ -3822,6 +3847,32 @@ default_make_symbol_completion_list (char *text, char *word)
       }
   }
 
+  if (current_language->la_macro_expansion)
+    {
+      struct macro_scope *scope;
+      struct add_macro_name_data datum;
+
+      datum.sym_text = sym_text;
+      datum.sym_text_len = sym_text_len;
+      datum.text = text;
+      datum.word = word;
+
+      /* Add any macros visible in the default scope.  Note that this
+	 may yield the occasional wrong result, because an expression
+	 might be evaluated in a scope other than the default.  There
+	 does not seem to be a way to detect this at completion time.  */
+      scope = default_macro_scope ();
+      if (scope)
+	{
+	  macro_for_each_in_scope (scope->file, scope->line,
+				   add_macro_name, &datum);
+	  xfree (scope);
+	}
+
+      /* User-defined macros are always visible.  */
+      macro_for_each (macro_user_macros, add_macro_name, &datum);
+    }
+
   return (return_val);
 }
 
diff --git a/gdb/testsuite/gdb.base/macscp.exp b/gdb/testsuite/gdb.base/macscp.exp
index 15d3f2f..290f040 100644
--- a/gdb/testsuite/gdb.base/macscp.exp
+++ b/gdb/testsuite/gdb.base/macscp.exp
@@ -477,3 +477,58 @@ gdb_test "print M" \
 gdb_test "macro expand SPLICE(x, y)" \
   "Token splicing is not implemented yet." \
   "macro splicing lexes correctly"
+
+
+# Completion tests.
+
+# The macro FIFTY_SEVEN is in scope at this point.
+send_gdb "p FIFTY_\t"
+gdb_expect  {
+        -re "^p FIFTY_SEVEN $"\
+            { send_gdb "\n"
+              gdb_expect {
+                      -re "^.* = 57.*$gdb_prompt $"\
+                                        { pass "complete 'p FIFTY_SEVEN'"}
+                      -re ".*$gdb_prompt $" { fail "complete 'p FIFTY_SEVEN'"}
+                      timeout           {fail "(timeout) complete 'p FIFTY_SEVEN'"}
+                     }
+            }
+        -re ".*$gdb_prompt $"       { fail "complete 'p FIFTY_SEVEN'" }
+        timeout         { fail "(timeout) complete 'p FIFTY_SEVEN' 2" }
+        }
+
+# The macro TWENTY_THREE is not in scope.
+send_gdb "p TWENTY_\t"
+gdb_expect  {
+        -re "^p TWENTY_\\\x07$"\
+            { send_gdb "\n"
+              gdb_expect {
+                      -re "No symbol \"TWENTY_\" in current context\\..*$gdb_prompt $"\
+                                        { pass "complete 'p TWENTY_'"}
+                      -re ".*$gdb_prompt $" { fail "complete 'p TWENTY_'"}
+                      timeout           {fail "(timeout) complete 'p TWENTY_'"}
+                     }
+            }
+        -re ".*$gdb_prompt $"       { fail "complete 'p TWENTY_'" }
+        timeout         { fail "(timeout) complete 'p TWENTY_' 2" }
+        }
+
+gdb_test "macro define TWENTY_THREE 25" \
+  "" \
+  "defining TWENTY_THREE"
+
+# User-defined macros are always in scope.
+send_gdb "p TWENTY_\t"
+gdb_expect  {
+        -re "^p TWENTY_THREE $"\
+            { send_gdb "\n"
+              gdb_expect {
+                      -re "^.* = 25.*$gdb_prompt $"\
+                                        { pass "complete 'p TWENTY_THREE'"}
+                      -re ".*$gdb_prompt $" { fail "complete 'p TWENTY_THREE'"}
+                      timeout           {fail "(timeout) complete 'p TWENTY_THREE'"}
+                     }
+            }
+        -re ".*$gdb_prompt $"       { fail "complete 'p TWENTY_THREE'" }
+        timeout         { fail "(timeout) complete 'p TWENTY_THREE' 2" }
+        }
diff --git a/gdb/testsuite/gdb.base/macscp1.c b/gdb/testsuite/gdb.base/macscp1.c
index 200ac26..3ac41c6 100644
--- a/gdb/testsuite/gdb.base/macscp1.c
+++ b/gdb/testsuite/gdb.base/macscp1.c
@@ -5,6 +5,8 @@
 #define STRINGIFY(a) INNER_STRINGIFY(a)
 #define INNER_STRINGIFY(a) #a
 
+#define FIFTY_SEVEN 57
+
 /* A macro named UNTIL_<func> is #defined until just before the
    definition of the function <func>.
 
@@ -75,6 +77,8 @@ macscp_expr (void)
   foo = 2;
 }
 
+#define TWENTY_THREE 23
+
 int
 main (int argc, char **argv)
 {


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