From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12516 invoked by alias); 21 Nov 2012 18:43:11 -0000 Received: (qmail 12219 invoked by uid 22791); 21 Nov 2012 18:43:08 -0000 X-SWARE-Spam-Status: No, hits=-5.9 required=5.0 tests=AWL,BAYES_00,KAM_STOCKGEN,KHOP_RCVD_UNTRUST,RCVD_IN_DNSWL_HI,RCVD_IN_HOSTKARMA_W,RP_MATCHES_RCVD,SPF_HELO_PASS,TW_BJ,TW_CP X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 21 Nov 2012 18:42:56 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id qALIguPA004156 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 21 Nov 2012 13:42:56 -0500 Received: from barimba (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id qALIgrhb007122 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Wed, 21 Nov 2012 13:42:53 -0500 From: Tom Tromey To: gdb-patches@sourceware.org Subject: [3/3] RFC: tag name completion Date: Wed, 21 Nov 2012 18:43:00 -0000 Message-ID: <87obiqlrv7.fsf@fleche.redhat.com> MIME-Version: 1.0 Content-Type: text/plain Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2012-11/txt/msg00584.txt.bz2 This implements tag name completion in the C parser. The basic idea is simple: if the user enters "struct X", then only struct tags starting with "X" should be considered. (And likewise for class, enum, and union.) The implementation is a bit hairy due to the need to pass this information via la_make_symbol_completion_list. I did this by adding a type_code argument and fixing the fallout. For Ada I simply added an assertion because this code cannot be called (since the Ada expression parser will never call mark_completion_tag). I think the rest of the patch is straightforward. Built and regtested on x86-64 Fedora 16. New test case included. Tom * ada-lang.c (ada_make_symbol_completion_list): Add 'code' argument, assertion. * c-exp.y (typebase): Add completion productions. * completer.c (expression_completer): Handle tag completion. * expression.h (parse_expression_for_completion): Add argument. * f-lang.c (f_make_symbol_completion_list): Add 'code' argument. * language.h (struct language_defn) : Add 'code' argument. * parse.c (expout_tag_completion_type, expout_completion_name): New globals. (mark_struct_expression): Add assertion. (mark_completion_tag): New function. (parse_exp_in_context): Initialize new globals. (parse_expression_for_completion): Add 'code' argument. Handle tag completion. * parser-defs.h (mark_completion_tag): Declare. * symtab.c (default_make_symbol_completion_list_break_on): Add 'code' argument. Update. (default_make_symbol_completion_list): Add 'code' argument. (make_symbol_completion_list): Update. (make_symbol_completion_type): New function. * symtab.h (default_make_symbol_completion_list_break_on) (default_make_symbol_completion_list): Update. (make_symbol_completion_type): Declare. * gdb.base/break1.c (enum some_enum, union some_union): New. (some_enum_global, some_union_global, some_value): New globals. * gdb.base/completion.exp: Add tag completion tests. --- gdb/ada-lang.c | 4 +- gdb/c-exp.y | 44 +++++++++++++++++ gdb/completer.c | 12 ++++- gdb/expression.h | 3 +- gdb/f-lang.c | 4 +- gdb/language.h | 7 ++- gdb/parse.c | 45 +++++++++++++++++- gdb/parser-defs.h | 4 ++ gdb/symtab.c | 86 ++++++++++++++++++++++++--------- gdb/symtab.h | 9 +++- gdb/testsuite/gdb.base/break1.c | 17 +++++++ gdb/testsuite/gdb.base/completion.exp | 8 +++ 12 files changed, 210 insertions(+), 33 deletions(-) diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index e1dced5..daa18dc 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -5802,7 +5802,7 @@ ada_expand_partial_symbol_name (const char *name, void *user_data) the entire command on which completion is made. */ static VEC (char_ptr) * -ada_make_symbol_completion_list (char *text0, char *word) +ada_make_symbol_completion_list (char *text0, char *word, enum type_code code) { char *text; int text_len; @@ -5817,6 +5817,8 @@ ada_make_symbol_completion_list (char *text0, char *word) int i; struct block_iterator iter; + gdb_assert (code == TYPE_CODE_UNDEF); + if (text0[0] == '<') { text = xstrdup (text0); diff --git a/gdb/c-exp.y b/gdb/c-exp.y index 23195e8..58edb53 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -1268,15 +1268,59 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */ | STRUCT name { $$ = lookup_struct (copy_name ($2), expression_context_block); } + | STRUCT COMPLETE + { + mark_completion_tag (TYPE_CODE_STRUCT, "", 0); + $$ = NULL; + } + | STRUCT name COMPLETE + { + mark_completion_tag (TYPE_CODE_STRUCT, $2.ptr, + $2.length); + $$ = NULL; + } | CLASS name { $$ = lookup_struct (copy_name ($2), expression_context_block); } + | CLASS COMPLETE + { + mark_completion_tag (TYPE_CODE_CLASS, "", 0); + $$ = NULL; + } + | CLASS name COMPLETE + { + mark_completion_tag (TYPE_CODE_CLASS, $2.ptr, + $2.length); + $$ = NULL; + } | UNION name { $$ = lookup_union (copy_name ($2), expression_context_block); } + | UNION COMPLETE + { + mark_completion_tag (TYPE_CODE_UNION, "", 0); + $$ = NULL; + } + | UNION name COMPLETE + { + mark_completion_tag (TYPE_CODE_UNION, $2.ptr, + $2.length); + $$ = NULL; + } | ENUM name { $$ = lookup_enum (copy_name ($2), expression_context_block); } + | ENUM COMPLETE + { + mark_completion_tag (TYPE_CODE_ENUM, "", 0); + $$ = NULL; + } + | ENUM name COMPLETE + { + mark_completion_tag (TYPE_CODE_ENUM, $2.ptr, + $2.length); + $$ = NULL; + } | UNSIGNED typename { $$ = lookup_unsigned_typename (parse_language, parse_gdbarch, diff --git a/gdb/completer.c b/gdb/completer.c index 7954c2c..946717d 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -390,13 +390,14 @@ expression_completer (struct cmd_list_element *ignore, struct type *type = NULL; char *fieldname, *p; volatile struct gdb_exception except; + enum type_code code = TYPE_CODE_UNDEF; /* Perform a tentative parse of the expression, to see whether a field completion is required. */ fieldname = NULL; TRY_CATCH (except, RETURN_MASK_ERROR) { - type = parse_expression_for_completion (text, &fieldname); + type = parse_expression_for_completion (text, &fieldname, &code); } if (except.reason < 0) return NULL; @@ -422,6 +423,15 @@ expression_completer (struct cmd_list_element *ignore, return result; } } + else if (fieldname && code != TYPE_CODE_UNDEF) + { + VEC (char_ptr) *result; + struct cleanup *cleanup = make_cleanup (xfree, fieldname); + + result = make_symbol_completion_type (fieldname, fieldname, code); + do_cleanups (cleanup); + return result; + } xfree (fieldname); /* Commands which complete on locations want to see the entire diff --git a/gdb/expression.h b/gdb/expression.h index 1a90cc1..b2077ca 100644 --- a/gdb/expression.h +++ b/gdb/expression.h @@ -98,7 +98,8 @@ struct expression extern struct expression *parse_expression (char *); -extern struct type *parse_expression_for_completion (char *, char **); +extern struct type *parse_expression_for_completion (char *, char **, + enum type_code *); extern struct expression *parse_exp_1 (char **, CORE_ADDR pc, struct block *, int); diff --git a/gdb/f-lang.c b/gdb/f-lang.c index 0b3645f..344d9b8 100644 --- a/gdb/f-lang.c +++ b/gdb/f-lang.c @@ -230,9 +230,9 @@ f_word_break_characters (void) class. */ static VEC (char_ptr) * -f_make_symbol_completion_list (char *text, char *word) +f_make_symbol_completion_list (char *text, char *word, enum type_code code) { - return default_make_symbol_completion_list_break_on (text, word, ":"); + return default_make_symbol_completion_list_break_on (text, word, ":", code); } const struct language_defn f_language_defn = diff --git a/gdb/language.h b/gdb/language.h index 3a1e390..49afbc4 100644 --- a/gdb/language.h +++ b/gdb/language.h @@ -284,8 +284,11 @@ struct language_defn /* Should return a vector of all symbols which are possible completions for TEXT. WORD is the entire command on which the - completion is being made. */ - VEC (char_ptr) *(*la_make_symbol_completion_list) (char *text, char *word); + completion is being made. If CODE is TYPE_CODE_UNDEF, then all + symbols should be examined; otherwise, only STRUCT_DOMAIN + symbols whose type has a code of CODE should be matched. */ + VEC (char_ptr) *(*la_make_symbol_completion_list) (char *text, char *word, + enum type_code code); /* The per-architecture (OS/ABI) language information. */ void (*la_language_arch_info) (struct gdbarch *, diff --git a/gdb/parse.c b/gdb/parse.c index d927ca2..0ecaaf1 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -88,6 +88,13 @@ int parse_completion; '->'. This is set when parsing and is only used when completing a field name. It is -1 if no dereference operation was found. */ static int expout_last_struct = -1; + +/* If we are completing a tagged type name, this will be nonzero. */ +static enum type_code expout_tag_completion_type = TYPE_CODE_UNDEF; + +/* The token for tagged type name completion. */ +static char *expout_completion_name; + static unsigned int expressiondebug = 0; static void @@ -578,9 +585,32 @@ write_exp_msymbol (struct minimal_symbol *msymbol) void mark_struct_expression (void) { + gdb_assert (parse_completion + && expout_tag_completion_type == TYPE_CODE_UNDEF); expout_last_struct = expout_ptr; } +/* Indicate that the current parser invocation is completing a tag. + TAG is the type code of the tag, and PTR and LENGTH represent the + start of the tag name. */ + +void +mark_completion_tag (enum type_code tag, const char *ptr, int length) +{ + gdb_assert (parse_completion + && expout_tag_completion_type == TYPE_CODE_UNDEF + && expout_completion_name == NULL + && expout_last_struct == -1); + gdb_assert (tag == TYPE_CODE_UNION + || tag == TYPE_CODE_STRUCT + || tag == TYPE_CODE_CLASS + || tag == TYPE_CODE_ENUM); + expout_tag_completion_type = tag; + expout_completion_name = xmalloc (length + 1); + memcpy (expout_completion_name, ptr, length); + expout_completion_name[length] = '\0'; +} + /* Recognize tokens that start with '$'. These include: @@ -1123,6 +1153,9 @@ parse_exp_in_context (char **stringptr, CORE_ADDR pc, struct block *block, paren_depth = 0; type_stack.depth = 0; expout_last_struct = -1; + expout_tag_completion_type = TYPE_CODE_UNDEF; + xfree (expout_completion_name); + expout_completion_name = NULL; comma_terminates = comma; @@ -1243,7 +1276,8 @@ parse_expression (char *string) *NAME must be freed by the caller. */ struct type * -parse_expression_for_completion (char *string, char **name) +parse_expression_for_completion (char *string, char **name, + enum type_code *code) { struct expression *exp = NULL; struct value *val; @@ -1258,6 +1292,15 @@ parse_expression_for_completion (char *string, char **name) parse_completion = 0; if (except.reason < 0 || ! exp) return NULL; + + if (expout_tag_completion_type != TYPE_CODE_UNDEF) + { + *code = expout_tag_completion_type; + *name = expout_completion_name; + expout_completion_name = NULL; + return NULL; + } + if (expout_last_struct == -1) { xfree (exp); diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h index c889d56..8e0f7c2 100644 --- a/gdb/parser-defs.h +++ b/gdb/parser-defs.h @@ -372,4 +372,8 @@ extern void parser_fprintf (FILE *, const char *, ...) ATTRIBUTE_PRINTF (2, 3); extern int exp_uses_objfile (struct expression *exp, struct objfile *objfile); +extern void mark_completion_tag (enum type_code, const char *ptr, + int length); + #endif /* PARSER_DEFS_H */ + diff --git a/gdb/symtab.c b/gdb/symtab.c index 05943cf..c9feee6 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -4200,7 +4200,8 @@ expand_partial_symbol_name (const char *name, void *user_data) VEC (char_ptr) * default_make_symbol_completion_list_break_on (char *text, char *word, - const char *break_on) + const char *break_on, + enum type_code code) { /* Problem: All of the symbols have to be copied because readline frees them. I'm not going to worry about this; hopefully there @@ -4307,13 +4308,18 @@ default_make_symbol_completion_list_break_on (char *text, char *word, anything that isn't a text symbol (everything else will be handled by the psymtab code above). */ - ALL_MSYMBOLS (objfile, msymbol) - { - QUIT; - COMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text, word); + if (code == TYPE_CODE_UNDEF) + { + ALL_MSYMBOLS (objfile, msymbol) + { + QUIT; + COMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text, + word); - completion_list_objc_symbol (msymbol, sym_text, sym_text_len, text, word); - } + completion_list_objc_symbol (msymbol, sym_text, sym_text_len, text, + word); + } + } /* Search upwards from currently selected frame (so that we can complete on local vars). Also catch fields of types defined in @@ -4330,10 +4336,17 @@ default_make_symbol_completion_list_break_on (char *text, char *word, ALL_BLOCK_SYMBOLS (b, iter, sym) { - COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, - word); - completion_list_add_fields (sym, sym_text, sym_text_len, text, - word); + if (code == TYPE_CODE_UNDEF) + { + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, + word); + completion_list_add_fields (sym, sym_text, sym_text_len, text, + word); + } + else if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN + && TYPE_CODE (SYMBOL_TYPE (sym)) == code) + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, + word); } /* Stop when we encounter an enclosing function. Do not stop for @@ -4346,13 +4359,16 @@ default_make_symbol_completion_list_break_on (char *text, char *word, /* Add fields from the file's types; symbols will be added below. */ - if (surrounding_static_block != NULL) - ALL_BLOCK_SYMBOLS (surrounding_static_block, iter, sym) - completion_list_add_fields (sym, sym_text, sym_text_len, text, word); + if (code == TYPE_CODE_UNDEF) + { + if (surrounding_static_block != NULL) + ALL_BLOCK_SYMBOLS (surrounding_static_block, iter, sym) + completion_list_add_fields (sym, sym_text, sym_text_len, text, word); - if (surrounding_global_block != NULL) - ALL_BLOCK_SYMBOLS (surrounding_global_block, iter, sym) - completion_list_add_fields (sym, sym_text, sym_text_len, text, word); + if (surrounding_global_block != NULL) + ALL_BLOCK_SYMBOLS (surrounding_global_block, iter, sym) + completion_list_add_fields (sym, sym_text, sym_text_len, text, word); + } /* Go through the symtabs and check the externs and statics for symbols which match. */ @@ -4363,7 +4379,10 @@ default_make_symbol_completion_list_break_on (char *text, char *word, b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK); ALL_BLOCK_SYMBOLS (b, iter, sym) { - COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + if (code == TYPE_CODE_UNDEF + || (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN + && TYPE_CODE (SYMBOL_TYPE (sym)) == code)) + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); } } @@ -4373,11 +4392,17 @@ default_make_symbol_completion_list_break_on (char *text, char *word, b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); ALL_BLOCK_SYMBOLS (b, iter, sym) { - COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + if (code == TYPE_CODE_UNDEF + || (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN + && TYPE_CODE (SYMBOL_TYPE (sym)) == code)) + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); } } - if (current_language->la_macro_expansion == macro_expansion_c) + /* Skip macros if we are completing a struct tag -- arguable but + usually what is expected. */ + if (current_language->la_macro_expansion == macro_expansion_c + && code == TYPE_CODE_UNDEF) { struct macro_scope *scope; @@ -4405,9 +4430,10 @@ default_make_symbol_completion_list_break_on (char *text, char *word, } VEC (char_ptr) * -default_make_symbol_completion_list (char *text, char *word) +default_make_symbol_completion_list (char *text, char *word, + enum type_code code) { - return default_make_symbol_completion_list_break_on (text, word, ""); + return default_make_symbol_completion_list_break_on (text, word, "", code); } /* Return a vector of all symbols (regardless of class) which begin by @@ -4417,7 +4443,21 @@ default_make_symbol_completion_list (char *text, char *word) VEC (char_ptr) * make_symbol_completion_list (char *text, char *word) { - return current_language->la_make_symbol_completion_list (text, word); + return current_language->la_make_symbol_completion_list (text, word, + TYPE_CODE_UNDEF); +} + +/* Like make_symbol_completion_list, but only return STRUCT_DOMAIN + symbols whose type code is CODE. */ + +VEC (char_ptr) * +make_symbol_completion_type (char *text, char *word, enum type_code code) +{ + gdb_assert (code == TYPE_CODE_UNION + || code == TYPE_CODE_STRUCT + || code == TYPE_CODE_CLASS + || code == TYPE_CODE_ENUM); + return current_language->la_make_symbol_completion_list (text, word, code); } /* Like make_symbol_completion_list, but suitable for use as a diff --git a/gdb/symtab.h b/gdb/symtab.h index 0d24cb5..a181da0 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -23,6 +23,7 @@ #include "vec.h" #include "gdb_vecs.h" +#include "gdbtypes.h" /* Opaque declarations. */ struct ui_file; @@ -1182,9 +1183,13 @@ extern void forget_cached_source_info (void); extern void select_source_symtab (struct symtab *); extern VEC (char_ptr) *default_make_symbol_completion_list_break_on - (char *text, char *word, const char *break_on); -extern VEC (char_ptr) *default_make_symbol_completion_list (char *, char *); + (char *text, char *word, const char *break_on, + enum type_code code); +extern VEC (char_ptr) *default_make_symbol_completion_list (char *, char *, + enum type_code); extern VEC (char_ptr) *make_symbol_completion_list (char *, char *); +extern VEC (char_ptr) *make_symbol_completion_type (char *, char *, + enum type_code); extern VEC (char_ptr) *make_symbol_completion_list_fn (struct cmd_list_element *, char *, char *); diff --git a/gdb/testsuite/gdb.base/break1.c b/gdb/testsuite/gdb.base/break1.c index af4f2b0..1f0654e 100644 --- a/gdb/testsuite/gdb.base/break1.c +++ b/gdb/testsuite/gdb.base/break1.c @@ -29,6 +29,23 @@ struct some_struct struct some_struct values[50]; +/* Some definitions for tag completion. */ +enum some_enum { VALUE }; + +enum some_enum some_enum_global; + +union some_union +{ + int f1; + double f2; +}; + +union some_union some_union_global; + +/* A variable with a name "similar" to the above struct, to test that + tag completion works ok. */ +int some_variable; + /* The following functions do nothing useful. They are included simply as places to try setting breakpoints at. They are explicitly "one-line functions" to verify that this case works diff --git a/gdb/testsuite/gdb.base/completion.exp b/gdb/testsuite/gdb.base/completion.exp index c8edc98..006670d 100644 --- a/gdb/testsuite/gdb.base/completion.exp +++ b/gdb/testsuite/gdb.base/completion.exp @@ -700,6 +700,14 @@ gdb_test "complete sav" "save" "test non-deprecated completion" gdb_test "complete save-t" "save-tracepoints" "test deprecated completion" +# +# Tag name completion. +# + +gdb_test "complete ptype struct some_" "ptype struct some_struct" +gdb_test "complete ptype enum some_" "ptype enum some_enum" +gdb_test "complete ptype union some_" "ptype union some_union" + # Restore globals modified in this test... set timeout $oldtimeout1 -- 1.7.7.6