From 5923a7f7516b57049ef4f62f7902990fcf31b163 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 19 May 2017 20:55:35 -0400 Subject: [PATCH 20/31] FIXME: enough to get find-defn-of-struct working --- gcc/blt.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/blt.def | 3 ++ gcc/blt.h | 23 ++++++++++ gcc/c/c-parser.c | 17 ++++++++ gcc/cp/parser.c | 2 + gcc/lsp-main.c | 97 ++++++++++++++++++++++++++++++++++++++--- 6 files changed, 265 insertions(+), 6 deletions(-) diff --git a/gcc/blt.c b/gcc/blt.c index 07b7819..d92149b 100644 --- a/gcc/blt.c +++ b/gcc/blt.c @@ -290,6 +290,19 @@ blt_node::get_children_of_kind (auto_vec &out, out.safe_push (child); } +int +blt_node::get_index_of_child (blt_node *needle) const +{ + int idx = 0; + for (blt_node *child = m_first_child; child; child = child->m_next_sibling) + { + if (child == needle) + return idx; + idx++; + } + return -1; +} + /* FIXME. */ blt_node * @@ -303,6 +316,120 @@ blt_node::get_ancestor_of_kind (enum blt_kind kind) const /* FIXME. */ +blt_node * +blt_node::find_descendant_satisfying (blt_predicate &pred) +{ + /* First, try to find within children, so that we get the deepest node + matching the criterion. */ + for (blt_node *child = m_first_child; child; child = child->m_next_sibling) + { + blt_node *within_child = child->find_descendant_satisfying (pred); + if (within_child) + return within_child; + } + + /* Try within this node. */ + if (pred.satisfied_by_node_p (*this)) + return this; + + return NULL; +} + +class contains_location_predicate : public blt_predicate +{ + public: + contains_location_predicate (const char *filename, int line, int character) + : m_filename (filename), m_line (line), m_character (character) {} + + bool satisfied_by_node_p (const blt_node &node) FINAL OVERRIDE + { + return node.contains_location_p (m_filename, m_line, m_character); + } + + private: + const char *m_filename; + int m_line; + int m_character; +}; + +/* FIXME. */ + +blt_node * +blt_node::get_descendant_at_location (const char *filename, int line, + int character) +{ + contains_location_predicate pred (filename, line, character); + return find_descendant_satisfying (pred); +} + +/* FIXME. */ + +bool +blt_node::contains_location_p (const char *filename, int row, int column) const +{ + expanded_location el_start = expand_location (m_start); + expanded_location el_finish = expand_location (m_finish); + + /* FIXME: share this with diagnostic-show-locus.c:layout_range. */ + + gcc_assert (el_start.line <= el_finish.line); + /* ...but the equivalent isn't true for the columns; + consider example B in the comment above. */ + + if (row < el_start.line) + /* Points before the first line of the range are + outside it (corresponding to line 01 in example A + and lines 01 and 02 in example B above). */ + return false; + + if (row == el_start.line) + /* On same line as start of range (corresponding + to line 02 in example A and line 03 in example B). */ + { + if (column < el_start.column) + /* Points on the starting line of the range, but + before the column in which it begins. */ + return false; + + if (row < el_finish.line) + /* This is a multiline range; the point + is within it (corresponds to line 03 in example B + from column 14 onwards) */ + return true; + else + { + /* This is a single-line range. */ + gcc_assert (row == el_finish.line); + return column <= el_finish.column; + } + } + + /* The point is in a line beyond that containing the + start of the range: lines 03 onwards in example A, + and lines 04 onwards in example B. */ + gcc_assert (row > el_start.line); + + if (row > el_finish.line) + /* The point is beyond the final line of the range + (lines 03 onwards in example A, and lines 06 onwards + in example B). */ + return false; + + if (row < el_finish.line) + { + /* The point is in a line that's fully within a multiline + range (e.g. line 04 in example B). */ + gcc_assert (el_start.line < el_finish.line); + return true; + } + + gcc_assert (row == el_finish.line); + + return column <= el_finish.column; +} + +/* FIXME. */ + void blt_node::assert_invariants () const { @@ -381,3 +508,5 @@ debug (blt_node *node) { node->dump (stderr); } + +blt_node *the_blt_root_node; diff --git a/gcc/blt.def b/gcc/blt.def index f1f3795..84b0c17 100644 --- a/gcc/blt.def +++ b/gcc/blt.def @@ -47,6 +47,7 @@ DEF_BLT_NODE (BLT_CV_QUALIFIER, "cv-qualifier") DEF_BLT_NODE (BLT_CV_QUALIFIER_SEQ, "cv-qualifier-seq") DEF_BLT_NODE (BLT_DECLARATION, "declaration") DEF_BLT_NODE (BLT_DECLARATION_SEQ, "declaration-seq") +DEF_BLT_NODE (BLT_DECLARATION_SPECIFIERS, "declaration-specifiers") DEF_BLT_NODE (BLT_DECLARATOR, "declarator") DEF_BLT_NODE (BLT_DECL_SPECIFIER, "decl-specifier") DEF_BLT_NODE (BLT_DECL_SPECIFIER_SEQ, "decl-specifier-seq") @@ -72,6 +73,8 @@ DEF_BLT_NODE (BLT_PARAMETER_LIST, "parameter-list") DEF_BLT_NODE (BLT_POSTFIX_EXPRESSION, "postfix-expression") DEF_BLT_NODE (BLT_PRIMARY_EXPRESSION, "primary-expression") DEF_BLT_NODE (BLT_SIMPLE_DECLARATION, "simple-declaration") +DEF_BLT_NODE (BLT_STRUCT_CONTENTS, "struct-contents") +DEF_BLT_NODE (BLT_STRUCT_OR_UNION_SPECIFIER, "struct-or-union-specifier") DEF_BLT_NODE (BLT_TEMPLATE_DECLARATION, "template-declaration") DEF_BLT_NODE (BLT_TEMPLATE_PARAMETER_LIST, "template-parameter-list") DEF_BLT_NODE (BLT_THROW_EXPRESSION, "throw-expression") diff --git a/gcc/blt.h b/gcc/blt.h index 909dd4e..b253938 100644 --- a/gcc/blt.h +++ b/gcc/blt.h @@ -54,6 +54,16 @@ enum blt_kind #undef DEF_BLT_NODE }; +class blt_node; + +/* Would use a lambda. */ + +class blt_predicate +{ + public: + virtual bool satisfied_by_node_p (const blt_node &node) = 0; +}; + /* A syntax node: either a token, a non-terminal, or a simplified set of non-terminals. */ @@ -91,8 +101,18 @@ public: void get_children_of_kind (auto_vec &out, enum blt_kind kind) const; + int get_index_of_child (blt_node *needle) const; + blt_node *get_ancestor_of_kind (enum blt_kind kind) const; + blt_node *find_descendant_satisfying (blt_predicate &pred); + + blt_node *get_descendant_at_location (const char *filename, int line, + int character); + + bool contains_location_p (const char *filename, int line, + int character) const; + private: void assert_invariants () const; @@ -119,4 +139,7 @@ extern void blt_set_node_for_tree (tree, blt_node *); extern void DEBUG_FUNCTION debug (blt_node *); +/* FIXME. */ +extern blt_node *the_blt_root_node; + #endif /* GCC_BLT_H */ diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 5c19a34..0150a6a 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -2486,6 +2486,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, bool alignspec_ok, bool auto_type_ok, enum c_lookahead_kind la) { + AUTO_BLT_NODE (parser, BLT_DECLARATION_SPECIFIERS); + bool attrs_ok = start_attr_ok; bool seen_type = specs->typespec_kind != ctsk_none; @@ -2971,6 +2973,8 @@ c_parser_enum_specifier (c_parser *parser) static struct c_typespec c_parser_struct_or_union_specifier (c_parser *parser) { + AUTO_BLT_NODE (parser, BLT_STRUCT_OR_UNION_SPECIFIER); + struct c_typespec ret; tree attrs; tree ident = NULL_TREE; @@ -3006,6 +3010,8 @@ c_parser_struct_or_union_specifier (c_parser *parser) { /* Parse a struct or union definition. Start the scope of the tag before parsing components. */ + AUTO_BLT_NODE (parser, BLT_STRUCT_CONTENTS); + struct c_struct_parse_info *struct_info; tree type = start_struct (struct_loc, code, ident, &struct_info); tree postfix_attrs; @@ -3114,6 +3120,10 @@ c_parser_struct_or_union_specifier (c_parser *parser) ret.expr = NULL_TREE; ret.expr_const_operands = true; timevar_pop (TV_PARSE_STRUCT); + + if (CURRENT_BLT_NODE) + CURRENT_BLT_NODE->set_tree (ret.spec); + return ret; } else if (!ident) @@ -3125,7 +3135,12 @@ c_parser_struct_or_union_specifier (c_parser *parser) ret.expr_const_operands = true; return ret; } + ret = parser_xref_tag (ident_loc, code, ident); + + if (CURRENT_BLT_NODE) + CURRENT_BLT_NODE->set_tree (ret.spec); + return ret; } @@ -18309,6 +18324,8 @@ c_parse_file (void) if (flag_blt && flag_dump_blt) the_parser->blt_root_node->dump (stderr); + the_blt_root_node = the_parser->blt_root_node; + the_parser = NULL; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b81c94d..1700a4e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -38771,6 +38771,8 @@ c_parse_file (void) if (flag_blt && flag_dump_blt) the_parser->blt_root_node->dump (stderr); + the_blt_root_node = the_parser->blt_root_node; + the_parser = NULL; } diff --git a/gcc/lsp-main.c b/gcc/lsp-main.c index 7866307..e971fc1 100644 --- a/gcc/lsp-main.c +++ b/gcc/lsp-main.c @@ -24,9 +24,54 @@ along with GCC; see the file COPYING3. If not see #include "json.h" #include "json-rpc.h" #include "lsp.h" +#include "blt.h" +#include "tree.h" using namespace lsp; +class is_record_definition : public blt_predicate +{ + public: + is_record_definition (tree record_type) : m_record_type (record_type) {} + + bool satisfied_by_node_p (const blt_node &node) FINAL OVERRIDE + { + if (node.get_kind () == BLT_STRUCT_CONTENTS + && node.get_tree () == m_record_type) + return true; + return false; + } + + private: + tree m_record_type; +}; + +static bool +Location_from_blt_node (const blt_node *node, Location &out) +{ + if (!node) + return false; + + location_t start = node->get_start (); + if (start == UNKNOWN_LOCATION) + return false; + location_t finish = node->get_finish (); + if (finish == UNKNOWN_LOCATION) + return false; + + expanded_location el_start = expand_location (start); + expanded_location el_finish = expand_location (finish); + if (el_start.file != el_finish.file) + return false; + + out.uri = el_start.file; + out.range.start.line = el_start.line; + out.range.start.character = el_start.column; + out.range.end.line = el_finish.line; + out.range.end.character = el_finish.column; + return true; +} + /* Implementation of lsp::server. Ideally we'd wire this up to GCC's IR. */ @@ -40,12 +85,52 @@ class gcc_lsp_server : public lsp::noop_server vec &out) OVERRIDE { /* TODO. */ - /* FIXME: currently, all we do is echo back the input location. */ - Location result; - result.uri = p.textDocument.uri; - result.range.start = p.position; - result.range.end = p.position; - out.safe_push (result); + blt_node *blt + = the_blt_root_node->get_descendant_at_location (p.textDocument.uri, + p.position.line, + p.position.character); + if (!blt) + /* No results. */ + return; + + blt->dump (stderr); + + switch (blt->get_kind ()) + { + case BLT_STRUCT_OR_UNION_SPECIFIER: + { + /* Attempt to locate the RECORD_TYPE for the + struct-or-union-specifier. */ + tree record_type = blt->get_tree (); + if (!record_type) + return; + + if (1) + the_blt_root_node->dump (stderr); + + /* Find a struct-contents with tree == record_type. */ + is_record_definition pred (record_type); + blt_node *blt_struct_contents + = the_blt_root_node->find_descendant_satisfying (pred); + if (!blt_struct_contents) + return; + + if (1) + blt_struct_contents->dump (stderr); + blt_node *blt_struct_defn = blt_struct_contents->get_parent (); + + Location result; + if (Location_from_blt_node (blt_struct_defn, result)) + out.safe_push (result); + } + break; + + default: + /* No results. */ + return; + } + + } }; -- 1.8.5.3