location_completer (ignore, tracker, text, NULL);
}
-/* Helper for expression_completer which recursively adds field and
- method names from TYPE, a struct or union type, to the OUTPUT
- list. */
-
-static void
-add_struct_fields (struct type *type, completion_list &output,
- const char *fieldname, int namelen)
-{
- int i;
- int computed_type_name = 0;
- const char *type_name = NULL;
-
- type = check_typedef (type);
- for (i = 0; i < type->num_fields (); ++i)
- {
- if (i < TYPE_N_BASECLASSES (type))
- add_struct_fields (TYPE_BASECLASS (type, i),
- output, fieldname, namelen);
- else if (type->field (i).name ())
- {
- if (type->field (i).name ()[0] != '\0')
- {
- if (! strncmp (type->field (i).name (),
- fieldname, namelen))
- output.emplace_back (xstrdup (type->field (i).name ()));
- }
- else if (type->field (i).type ()->code () == TYPE_CODE_UNION)
- {
- /* Recurse into anonymous unions. */
- add_struct_fields (type->field (i).type (),
- output, fieldname, namelen);
- }
- }
- }
-
- for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i)
- {
- const char *name = TYPE_FN_FIELDLIST_NAME (type, i);
-
- if (name && ! strncmp (name, fieldname, namelen))
- {
- if (!computed_type_name)
- {
- type_name = type->name ();
- computed_type_name = 1;
- }
- /* Omit constructors from the completion list. */
- if (!type_name || strcmp (type_name, name))
- output.emplace_back (xstrdup (name));
- }
- }
-}
-
/* See completer.h. */
void
complete_expression (completion_tracker &tracker,
const char *text, const char *word)
{
- struct type *type = NULL;
- gdb::unique_xmalloc_ptr<char> fieldname;
- enum type_code code = TYPE_CODE_UNDEF;
+ expression_up exp;
+ std::unique_ptr<expr_completion_base> expr_completer;
/* Perform a tentative parse of the expression, to see whether a
field completion is required. */
try
{
- type = parse_expression_for_completion (text, &fieldname, &code);
+ exp = parse_expression_for_completion (text, &expr_completer);
}
catch (const gdb_exception_error &except)
{
return;
}
- if (fieldname != nullptr && type)
- {
- for (;;)
- {
- type = check_typedef (type);
- if (!type->is_pointer_or_reference ())
- break;
- type = TYPE_TARGET_TYPE (type);
- }
-
- if (type->code () == TYPE_CODE_UNION
- || type->code () == TYPE_CODE_STRUCT)
- {
- completion_list result;
-
- add_struct_fields (type, result, fieldname.get (),
- strlen (fieldname.get ()));
- tracker.add_completions (std::move (result));
- return;
- }
- }
- else if (fieldname != nullptr && code != TYPE_CODE_UNDEF)
- {
- collect_symbol_completion_matches_type (tracker, fieldname.get (),
- fieldname.get (), code);
- return;
- }
+ /* Part of the parse_expression_for_completion contract. */
+ gdb_assert ((exp == nullptr) == (expr_completer == nullptr));
+ if (expr_completer != nullptr
+ && expr_completer->complete (exp.get (), tracker))
+ return;
complete_files_symbols (tracker, text, word);
}
nullptr, expect_type);
}
+/* Helper for structop_base_operation::complete which recursively adds
+ field and method names from TYPE, a struct or union type, to the
+ OUTPUT list. */
+
+static void
+add_struct_fields (struct type *type, completion_list &output,
+ const char *fieldname, int namelen)
+{
+ int i;
+ int computed_type_name = 0;
+ const char *type_name = NULL;
+
+ type = check_typedef (type);
+ for (i = 0; i < type->num_fields (); ++i)
+ {
+ if (i < TYPE_N_BASECLASSES (type))
+ add_struct_fields (TYPE_BASECLASS (type, i),
+ output, fieldname, namelen);
+ else if (type->field (i).name ())
+ {
+ if (type->field (i).name ()[0] != '\0')
+ {
+ if (! strncmp (type->field (i).name (),
+ fieldname, namelen))
+ output.emplace_back (xstrdup (type->field (i).name ()));
+ }
+ else if (type->field (i).type ()->code () == TYPE_CODE_UNION)
+ {
+ /* Recurse into anonymous unions. */
+ add_struct_fields (type->field (i).type (),
+ output, fieldname, namelen);
+ }
+ }
+ }
+
+ for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i)
+ {
+ const char *name = TYPE_FN_FIELDLIST_NAME (type, i);
+
+ if (name && ! strncmp (name, fieldname, namelen))
+ {
+ if (!computed_type_name)
+ {
+ type_name = type->name ();
+ computed_type_name = 1;
+ }
+ /* Omit constructors from the completion list. */
+ if (!type_name || strcmp (type_name, name))
+ output.emplace_back (xstrdup (name));
+ }
+ }
+}
+
+/* See expop.h. */
+
+bool
+structop_base_operation::complete (struct expression *exp,
+ completion_tracker &tracker)
+{
+ const std::string &fieldname = std::get<1> (m_storage);
+
+ value *lhs = std::get<0> (m_storage)->evaluate (nullptr, exp,
+ EVAL_AVOID_SIDE_EFFECTS);
+ struct type *type = value_type (lhs);
+ for (;;)
+ {
+ type = check_typedef (type);
+ if (!type->is_pointer_or_reference ())
+ break;
+ type = TYPE_TARGET_TYPE (type);
+ }
+
+ if (type->code () == TYPE_CODE_UNION
+ || type->code () == TYPE_CODE_STRUCT)
+ {
+ completion_list result;
+
+ add_struct_fields (type, result, fieldname.c_str (),
+ fieldname.length ());
+ tracker.add_completions (std::move (result));
+ return true;
+ }
+
+ return false;
+}
} /* namespace expr */
return std::get<1> (m_storage);
}
- /* Used for completion. Evaluate the LHS for type. */
- value *evaluate_lhs (struct expression *exp)
- {
- return std::get<0> (m_storage)->evaluate (nullptr, exp,
- EVAL_AVOID_SIDE_EFFECTS);
- }
-
value *evaluate_funcall (struct type *expect_type,
struct expression *exp,
enum noside noside,
const std::vector<operation_up> &args) override;
+ /* Try to complete this operation in the context of EXP. TRACKER is
+ the completion tracker to update. Return true if completion was
+ possible, false otherwise. */
+ bool complete (struct expression *exp, completion_tracker &tracker);
+
protected:
using tuple_holding_operation::tuple_holding_operation;
extern expression_up parse_expression_with_language (const char *string,
enum language lang);
-extern struct type *parse_expression_for_completion
- (const char *, gdb::unique_xmalloc_ptr<char> *, enum type_code *);
+
+class completion_tracker;
+
+/* Base class for expression completion. An instance of this
+ represents a completion request from the parser. */
+struct expr_completion_base
+{
+ /* Perform this object's completion. EXP is the expression in which
+ the completion occurs. TRACKER is the tracker to update with the
+ results. Return true if completion was possible (even if no
+ completions were found), false to fall back to ordinary
+ expression completion (i.e., symbol names). */
+ virtual bool complete (struct expression *exp,
+ completion_tracker &tracker) = 0;
+
+ virtual ~expr_completion_base () = default;
+};
+
+extern expression_up parse_expression_for_completion
+ (const char *, std::unique_ptr<expr_completion_base> *completer);
class innermost_block_tracker;
extern expression_up parse_exp_1 (const char **, CORE_ADDR pc,
}
-static expression_up parse_exp_in_context (const char **, CORE_ADDR,
- const struct block *, int,
- bool, innermost_block_tracker *,
- expr_completion_state *);
+static expression_up parse_exp_in_context
+ (const char **, CORE_ADDR,
+ const struct block *, int,
+ bool, innermost_block_tracker *,
+ std::unique_ptr<expr_completion_base> *);
/* Documented at it's declaration. */
}
}
+bool
+expr_complete_tag::complete (struct expression *exp,
+ completion_tracker &tracker)
+{
+ collect_symbol_completion_matches_type (tracker, m_name.get (),
+ m_name.get (), m_code);
+ return true;
+}
+
/* See parser-defs.h. */
void
parser_state::mark_struct_expression (expr::structop_base_operation *op)
{
- gdb_assert (parse_completion
- && (m_completion_state.expout_tag_completion_type
- == TYPE_CODE_UNDEF));
- m_completion_state.expout_last_op = op;
+ gdb_assert (parse_completion && m_completion_state == nullptr);
+ m_completion_state.reset (new expr_complete_structop (op));
}
/* Indicate that the current parser invocation is completing a tag.
parser_state::mark_completion_tag (enum type_code tag, const char *ptr,
int length)
{
- gdb_assert (parse_completion
- && (m_completion_state.expout_tag_completion_type
- == TYPE_CODE_UNDEF)
- && m_completion_state.expout_completion_name == NULL
- && m_completion_state.expout_last_op == nullptr);
+ gdb_assert (parse_completion && m_completion_state == nullptr);
gdb_assert (tag == TYPE_CODE_UNION
|| tag == TYPE_CODE_STRUCT
|| tag == TYPE_CODE_ENUM);
- m_completion_state.expout_tag_completion_type = tag;
- m_completion_state.expout_completion_name
- = make_unique_xstrndup (ptr, length);
+ m_completion_state.reset
+ (new expr_complete_tag (tag, make_unique_xstrndup (ptr, length)));
}
/* See parser-defs.h. */
const struct block *block,
int comma, bool void_context_p,
innermost_block_tracker *tracker,
- expr_completion_state *cstate)
+ std::unique_ptr<expr_completion_base> *completer)
{
const struct language_defn *lang = NULL;
parser_state ps (lang, get_current_arch (), expression_context_block,
expression_context_pc, comma, *stringptr,
- cstate != nullptr, tracker, void_context_p);
+ completer != nullptr, tracker, void_context_p);
scoped_restore_current_language lang_saver;
set_language (lang->la_language);
if (expressiondebug)
dump_prefix_expression (result.get (), gdb_stdlog);
- if (cstate != nullptr)
- *cstate = std::move (ps.m_completion_state);
+ if (completer != nullptr)
+ *completer = std::move (ps.m_completion_state);
*stringptr = ps.lexptr;
return result;
}
return parse_expression (string);
}
-/* Parse STRING as an expression. If parsing ends in the middle of a
- field reference, return the type of the left-hand-side of the
- reference; furthermore, if the parsing ends in the field name,
- return the field name in *NAME. If the parsing ends in the middle
- of a field reference, but the reference is somehow invalid, throw
- an exception. In all other cases, return NULL. */
-
-struct type *
-parse_expression_for_completion (const char *string,
- gdb::unique_xmalloc_ptr<char> *name,
- enum type_code *code)
+/* Parse STRING as an expression. If the parse is marked for
+ completion, set COMPLETER and return the expression. In all other
+ cases, return NULL. */
+
+expression_up
+parse_expression_for_completion
+ (const char *string,
+ std::unique_ptr<expr_completion_base> *completer)
{
expression_up exp;
- expr_completion_state cstate;
try
{
- exp = parse_exp_in_context (&string, 0, 0, 0, false, nullptr, &cstate);
+ exp = parse_exp_in_context (&string, 0, 0, 0, false, nullptr, completer);
}
catch (const gdb_exception_error &except)
{
/* Nothing, EXP remains NULL. */
}
- if (exp == NULL)
- return NULL;
-
- if (cstate.expout_tag_completion_type != TYPE_CODE_UNDEF)
- {
- *code = cstate.expout_tag_completion_type;
- *name = std::move (cstate.expout_completion_name);
- return NULL;
- }
-
- if (cstate.expout_last_op == nullptr)
+ /* If we didn't get a completion result, be sure to also not return
+ an expression to our caller. */
+ if (*completer == nullptr)
return nullptr;
- expr::structop_base_operation *op = cstate.expout_last_op;
- const std::string &fld = op->get_string ();
- *name = make_unique_xstrdup (fld.c_str ());
- return value_type (op->evaluate_lhs (exp.get ()));
+ return exp;
}
/* Parse floating point value P of length LEN.
expression_up expout;
};
-/* This is used for expression completion. */
+/* Complete an expression that references a field, like "x->y". */
-struct expr_completion_state
+struct expr_complete_structop : public expr_completion_base
{
+ explicit expr_complete_structop (expr::structop_base_operation *op)
+ : m_op (op)
+ {
+ }
+
+ bool complete (struct expression *exp,
+ completion_tracker &tracker) override
+ {
+ return m_op->complete (exp, tracker);
+ }
+
+private:
+
/* The last struct expression directly before a '.' or '->'. This
is set when parsing and is only used when completing a field
name. It is nullptr if no dereference operation was found. */
- expr::structop_base_operation *expout_last_op = nullptr;
+ expr::structop_base_operation *m_op = nullptr;
+};
+
+/* Complete a tag name in an expression. This is used for something
+ like "enum abc<TAB>". */
+
+struct expr_complete_tag : public expr_completion_base
+{
+ expr_complete_tag (enum type_code code,
+ gdb::unique_xmalloc_ptr<char> name)
+ : m_code (code),
+ m_name (std::move (name))
+ {
+ /* Parsers should enforce this statically. */
+ gdb_assert (code == TYPE_CODE_ENUM
+ || code == TYPE_CODE_UNION
+ || code == TYPE_CODE_STRUCT);
+ }
+
+ bool complete (struct expression *exp,
+ completion_tracker &tracker) override;
+
+private:
- /* If we are completing a tagged type name, this will be nonzero. */
- enum type_code expout_tag_completion_type = TYPE_CODE_UNDEF;
+ /* The kind of tag to complete. */
+ enum type_code m_code;
/* The token for tagged type name completion. */
- gdb::unique_xmalloc_ptr<char> expout_completion_name;
+ gdb::unique_xmalloc_ptr<char> m_name;
};
/* An instance of this type is instantiated during expression parsing,
bool parse_completion;
/* Completion state is updated here. */
- expr_completion_state m_completion_state;
+ std::unique_ptr<expr_completion_base> m_completion_state;
/* The innermost block tracker. */
innermost_block_tracker *block_tracker;