/* Implementation of gcc_rich_location class
- Copyright (C) 2014-2017 Free Software Foundation, Inc.
+ Copyright (C) 2014-2019 Free Software Foundation, Inc.
This file is part of GCC.
#include "tm.h"
#include "rtl.h"
#include "hash-set.h"
-#include "machmode.h"
#include "vec.h"
-#include "double-int.h"
#include "input.h"
#include "alias.h"
#include "symtab.h"
-#include "wide-int.h"
#include "inchash.h"
#include "tree-core.h"
#include "tree.h"
#include "cpplib.h"
#include "diagnostic.h"
-/* Add a range to the rich_location, covering expression EXPR. */
+/* Add a range to the rich_location, covering expression EXPR,
+ using LABEL if non-NULL. */
void
-gcc_rich_location::add_expr (tree expr)
+gcc_rich_location::add_expr (tree expr, range_label *label)
{
gcc_assert (expr);
if (CAN_HAVE_RANGE_P (expr))
- add_range (EXPR_LOCATION (expr), false);
+ add_range (EXPR_LOCATION (expr), SHOW_RANGE_WITHOUT_CARET, label);
}
-/* If T is an expression, add a range for it to the rich_location. */
+/* If T is an expression, add a range for it to the rich_location,
+ using LABEL if non-NULL. */
void
-gcc_rich_location::maybe_add_expr (tree t)
+gcc_rich_location::maybe_add_expr (tree t, range_label *label)
{
if (EXPR_P (t))
- add_expr (t);
+ add_expr (t, label);
}
/* Add a fixit hint suggesting replacing the range at MISSPELLED_TOKEN_LOC
add_fixit_replace (misspelled_token_loc, IDENTIFIER_POINTER (hint_id));
}
+
+/* Return true if there is nothing on LOC's line before LOC. */
+
+static bool
+blank_line_before_p (location_t loc)
+{
+ expanded_location exploc = expand_location (loc);
+ char_span line = location_get_source_line (exploc.file, exploc.line);
+ if (!line)
+ return false;
+ if (line.length () < (size_t)exploc.column)
+ return false;
+ /* Columns are 1-based. */
+ for (int column = 1; column < exploc.column; ++column)
+ if (!ISSPACE (line[column - 1]))
+ return false;
+ return true;
+}
+
+/* Subroutine of gcc_rich_location::add_fixit_insert_formatted.
+ Return true if we should add the content on its own line,
+ false otherwise.
+ If true is returned then *OUT_START_OF_LINE is written to. */
+
+static bool
+use_new_line (location_t insertion_point, location_t indent,
+ location_t *out_start_of_line)
+{
+ if (indent == UNKNOWN_LOCATION)
+ return false;
+ const line_map *indent_map = linemap_lookup (line_table, indent);
+ if (linemap_macro_expansion_map_p (indent_map))
+ return false;
+
+ if (!blank_line_before_p (insertion_point))
+ return false;
+
+ /* Locate the start of the line containing INSERTION_POINT. */
+ const line_map *insertion_point_map
+ = linemap_lookup (line_table, insertion_point);
+ if (linemap_macro_expansion_map_p (insertion_point_map))
+ return false;
+ const line_map_ordinary *ordmap
+ = linemap_check_ordinary (insertion_point_map);
+ expanded_location exploc_insertion_point = expand_location (insertion_point);
+ location_t start_of_line
+ = linemap_position_for_line_and_column (line_table, ordmap,
+ exploc_insertion_point.line, 1);
+ *out_start_of_line = start_of_line;
+ return true;
+}
+
+/* Add a fix-it hint suggesting the insertion of CONTENT before
+ INSERTION_POINT.
+
+ Attempt to handle formatting: if INSERTION_POINT is the first thing on
+ its line, and INDENT is sufficiently sane, then add CONTENT on its own
+ line, using the indentation of INDENT.
+ Otherwise, add CONTENT directly before INSERTION_POINT.
+
+ For example, adding "CONTENT;" with the closing brace as the insertion
+ point and "INDENT;" as the indentation point:
+
+ if ()
+ {
+ INDENT;
+ }
+
+ would lead to:
+
+ if ()
+ {
+ INDENT;
+ CONTENT;
+ }
+
+ but adding it to:
+
+ if () {INDENT;}
+
+ would lead to:
+
+ if () {INDENT;CONTENT;}
+*/
+
+void
+gcc_rich_location::add_fixit_insert_formatted (const char *content,
+ location_t insertion_point,
+ location_t indent)
+{
+ location_t start_of_line;
+ if (use_new_line (insertion_point, indent, &start_of_line))
+ {
+ /* Add CONTENT on its own line, using the indentation of INDENT. */
+
+ /* Generate an insertion string, indenting by the amount INDENT
+ was indented. */
+ int indent_column = LOCATION_COLUMN (get_start (indent));
+ pretty_printer tmp_pp;
+ pretty_printer *pp = &tmp_pp;
+ /* Columns are 1-based. */
+ for (int column = 1; column < indent_column; ++column)
+ pp_space (pp);
+ pp_string (pp, content);
+ pp_newline (pp);
+
+ add_fixit_insert_before (start_of_line, pp_formatted_text (pp));
+ }
+ else
+ add_fixit_insert_before (insertion_point, content);
+}
+
+/* Implementation of range_label::get_text for
+ maybe_range_label_for_tree_type_mismatch.
+
+ If both expressions are non-NULL, then generate text describing
+ the first expression's type (using the other expression's type
+ for comparison, analogous to %H and %I in the C++ frontend, but
+ on expressions rather than types). */
+
+label_text
+maybe_range_label_for_tree_type_mismatch::get_text (unsigned range_idx) const
+{
+ if (m_expr == NULL_TREE
+ || !EXPR_P (m_expr))
+ return label_text (NULL, false);
+ tree expr_type = TREE_TYPE (m_expr);
+
+ tree other_type = NULL_TREE;
+ if (m_other_expr && EXPR_P (m_other_expr))
+ other_type = TREE_TYPE (m_other_expr);
+
+ range_label_for_type_mismatch inner (expr_type, other_type);
+ return inner.get_text (range_idx);
+}
+
+/* binary_op_rich_location's ctor.
+
+ If use_operator_loc_p (LOC, ARG0, ARG1), then attempt to make a 3-location
+ rich_location of the form:
+
+ arg_0 op arg_1
+ ~~~~~ ^~ ~~~~~
+ | |
+ | arg1 type
+ arg0 type
+
+ labelling the types of the arguments if SHOW_TYPES is true.
+
+ Otherwise, make a 1-location rich_location using the compound
+ location within LOC:
+
+ arg_0 op arg_1
+ ~~~~~~^~~~~~~~
+
+ for which we can't label the types. */
+
+binary_op_rich_location::binary_op_rich_location (const op_location_t &loc,
+ tree arg0, tree arg1,
+ bool show_types)
+: gcc_rich_location (loc.m_combined_loc),
+ m_label_for_arg0 (arg0, arg1),
+ m_label_for_arg1 (arg1, arg0)
+{
+ /* Default (above) to using the combined loc.
+ Potentially override it here: if we have location information for the
+ operator and for both arguments, then split them all out.
+ Alternatively, override it if we don't have the combined location. */
+ if (use_operator_loc_p (loc, arg0, arg1))
+ {
+ set_range (0, loc.m_operator_loc, SHOW_RANGE_WITH_CARET);
+ maybe_add_expr (arg0, show_types ? &m_label_for_arg0 : NULL);
+ maybe_add_expr (arg1, show_types ? &m_label_for_arg1 : NULL);
+ }
+}
+
+/* Determine if binary_op_rich_location's ctor should attempt to make
+ a 3-location rich_location (the location of the operator and of
+ the 2 arguments), or fall back to a 1-location rich_location showing
+ just the combined location of the operation as a whole. */
+
+bool
+binary_op_rich_location::use_operator_loc_p (const op_location_t &loc,
+ tree arg0, tree arg1)
+{
+ /* If we don't have a combined location, then use the operator location,
+ and try to add ranges for the operators. */
+ if (loc.m_combined_loc == UNKNOWN_LOCATION)
+ return true;
+
+ /* If we don't have the operator location, then use the
+ combined location. */
+ if (loc.m_operator_loc == UNKNOWN_LOCATION)
+ return false;
+
+ /* We have both operator location and combined location: only use the
+ operator location if we have locations for both arguments. */
+ return (EXPR_HAS_LOCATION (arg0)
+ && EXPR_HAS_LOCATION (arg1));
+}