13ad841b2Smrg /* Determining the results of applying fix-it hints.
2*4c3eb207Smrg Copyright (C) 2016-2020 Free Software Foundation, Inc.
33ad841b2Smrg
43ad841b2Smrg This file is part of GCC.
53ad841b2Smrg
63ad841b2Smrg GCC is free software; you can redistribute it and/or modify it under
73ad841b2Smrg the terms of the GNU General Public License as published by the Free
83ad841b2Smrg Software Foundation; either version 3, or (at your option) any later
93ad841b2Smrg version.
103ad841b2Smrg
113ad841b2Smrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
123ad841b2Smrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
133ad841b2Smrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
143ad841b2Smrg for more details.
153ad841b2Smrg
163ad841b2Smrg You should have received a copy of the GNU General Public License
173ad841b2Smrg along with GCC; see the file COPYING3. If not see
183ad841b2Smrg <http://www.gnu.org/licenses/>. */
193ad841b2Smrg
203ad841b2Smrg #include "config.h"
213ad841b2Smrg #include "system.h"
223ad841b2Smrg #include "coretypes.h"
233ad841b2Smrg #include "line-map.h"
243ad841b2Smrg #include "edit-context.h"
253ad841b2Smrg #include "pretty-print.h"
263ad841b2Smrg #include "diagnostic-color.h"
273ad841b2Smrg #include "selftest.h"
283ad841b2Smrg
293ad841b2Smrg /* This file implements a way to track the effect of fix-its,
303ad841b2Smrg via a class edit_context; the other classes are support classes for
313ad841b2Smrg edit_context.
323ad841b2Smrg
333ad841b2Smrg A complication here is that fix-its are expressed relative to coordinates
343ad841b2Smrg in the file when it was parsed, before any changes have been made, and
353ad841b2Smrg so if there's more that one fix-it to be applied, we have to adjust
363ad841b2Smrg later fix-its to allow for the changes made by earlier ones. This
373ad841b2Smrg is done by the various "get_effective_column" methods.
383ad841b2Smrg
393ad841b2Smrg The "filename" params are required to outlive the edit_context (no
403ad841b2Smrg copy of the underlying str is taken, just the ptr). */
413ad841b2Smrg
423ad841b2Smrg /* Forward decls. class edit_context is declared within edit-context.h.
433ad841b2Smrg The other types are declared here. */
443ad841b2Smrg class edit_context;
453ad841b2Smrg class edited_file;
463ad841b2Smrg class edited_line;
473ad841b2Smrg class line_event;
483ad841b2Smrg
493ad841b2Smrg /* A struct to hold the params of a print_diff call. */
503ad841b2Smrg
51*4c3eb207Smrg class diff
523ad841b2Smrg {
53*4c3eb207Smrg public:
diff(pretty_printer * pp,bool show_filenames)543ad841b2Smrg diff (pretty_printer *pp, bool show_filenames)
553ad841b2Smrg : m_pp (pp), m_show_filenames (show_filenames) {}
563ad841b2Smrg
573ad841b2Smrg pretty_printer *m_pp;
583ad841b2Smrg bool m_show_filenames;
593ad841b2Smrg };
603ad841b2Smrg
613ad841b2Smrg /* The state of one named file within an edit_context: the filename,
623ad841b2Smrg and the lines that have been edited so far. */
633ad841b2Smrg
643ad841b2Smrg class edited_file
653ad841b2Smrg {
663ad841b2Smrg public:
673ad841b2Smrg edited_file (const char *filename);
683ad841b2Smrg static void delete_cb (edited_file *file);
693ad841b2Smrg
get_filename()703ad841b2Smrg const char *get_filename () const { return m_filename; }
713ad841b2Smrg char *get_content ();
723ad841b2Smrg
73cef8759bSmrg bool apply_fixit (int line, int start_column,
74cef8759bSmrg int next_column,
753ad841b2Smrg const char *replacement_str,
763ad841b2Smrg int replacement_len);
773ad841b2Smrg int get_effective_column (int line, int column);
783ad841b2Smrg
call_print_diff(const char *,edited_file * file,void * user_data)793ad841b2Smrg static int call_print_diff (const char *, edited_file *file,
803ad841b2Smrg void *user_data)
813ad841b2Smrg {
823ad841b2Smrg diff *d = (diff *)user_data;
833ad841b2Smrg file->print_diff (d->m_pp, d->m_show_filenames);
843ad841b2Smrg return 0;
853ad841b2Smrg }
863ad841b2Smrg
873ad841b2Smrg private:
883ad841b2Smrg bool print_content (pretty_printer *pp);
893ad841b2Smrg void print_diff (pretty_printer *pp, bool show_filenames);
90cef8759bSmrg int print_diff_hunk (pretty_printer *pp, int old_start_of_hunk,
91cef8759bSmrg int old_end_of_hunk, int new_start_of_hunk);
923ad841b2Smrg edited_line *get_line (int line);
933ad841b2Smrg edited_line *get_or_insert_line (int line);
943ad841b2Smrg int get_num_lines (bool *missing_trailing_newline);
953ad841b2Smrg
96cef8759bSmrg int get_effective_line_count (int old_start_of_hunk,
97cef8759bSmrg int old_end_of_hunk);
98cef8759bSmrg
99cef8759bSmrg void print_run_of_changed_lines (pretty_printer *pp,
100cef8759bSmrg int start_of_run,
101cef8759bSmrg int end_of_run);
102cef8759bSmrg
1033ad841b2Smrg const char *m_filename;
1043ad841b2Smrg typed_splay_tree<int, edited_line *> m_edited_lines;
1053ad841b2Smrg int m_num_lines;
1063ad841b2Smrg };
1073ad841b2Smrg
108cef8759bSmrg /* A line added before an edited_line. */
109cef8759bSmrg
110cef8759bSmrg class added_line
111cef8759bSmrg {
112cef8759bSmrg public:
added_line(const char * content,int len)113cef8759bSmrg added_line (const char *content, int len)
114cef8759bSmrg : m_content (xstrndup (content, len)), m_len (len) {}
~added_line()115cef8759bSmrg ~added_line () { free (m_content); }
116cef8759bSmrg
get_content()117cef8759bSmrg const char *get_content () const { return m_content; }
get_len()118cef8759bSmrg int get_len () const { return m_len; }
119cef8759bSmrg
120cef8759bSmrg private:
121cef8759bSmrg char *m_content;
122cef8759bSmrg int m_len;
123cef8759bSmrg };
124cef8759bSmrg
1253ad841b2Smrg /* The state of one edited line within an edited_file.
1263ad841b2Smrg As well as the current content of the line, it contains a record of
1273ad841b2Smrg the changes, so that further changes can be applied in the correct
128cef8759bSmrg place.
129cef8759bSmrg
130cef8759bSmrg When handling fix-it hints containing newlines, new lines are added
131cef8759bSmrg as added_line predecessors to an edited_line. Hence it's possible
132cef8759bSmrg for an "edited_line" to not actually have been changed, but to merely
133cef8759bSmrg be a placeholder for the lines added before it. This can be tested
134cef8759bSmrg for with actuall_edited_p, and has a slight effect on how diff hunks
135cef8759bSmrg are generated. */
1363ad841b2Smrg
1373ad841b2Smrg class edited_line
1383ad841b2Smrg {
1393ad841b2Smrg public:
1403ad841b2Smrg edited_line (const char *filename, int line_num);
1413ad841b2Smrg ~edited_line ();
1423ad841b2Smrg static void delete_cb (edited_line *el);
1433ad841b2Smrg
get_line_num()1443ad841b2Smrg int get_line_num () const { return m_line_num; }
get_content()1453ad841b2Smrg const char *get_content () const { return m_content; }
get_len()1463ad841b2Smrg int get_len () const { return m_len; }
1473ad841b2Smrg
1483ad841b2Smrg int get_effective_column (int orig_column) const;
149cef8759bSmrg bool apply_fixit (int start_column,
150cef8759bSmrg int next_column,
1513ad841b2Smrg const char *replacement_str,
1523ad841b2Smrg int replacement_len);
1533ad841b2Smrg
154cef8759bSmrg int get_effective_line_count () const;
155cef8759bSmrg
156cef8759bSmrg /* Has the content of this line actually changed, or are we merely
157cef8759bSmrg recording predecessor added_lines? */
actually_edited_p()158cef8759bSmrg bool actually_edited_p () const { return m_line_events.length () > 0; }
159cef8759bSmrg
160cef8759bSmrg void print_content (pretty_printer *pp) const;
161cef8759bSmrg void print_diff_lines (pretty_printer *pp) const;
162cef8759bSmrg
1633ad841b2Smrg private:
1643ad841b2Smrg void ensure_capacity (int len);
1653ad841b2Smrg void ensure_terminated ();
1663ad841b2Smrg
1673ad841b2Smrg int m_line_num;
1683ad841b2Smrg char *m_content;
1693ad841b2Smrg int m_len;
1703ad841b2Smrg int m_alloc_sz;
171cef8759bSmrg auto_vec <line_event> m_line_events;
172cef8759bSmrg auto_vec <added_line *> m_predecessors;
1733ad841b2Smrg };
1743ad841b2Smrg
175cef8759bSmrg /* Class for representing edit events that have occurred on one line of
176cef8759bSmrg one file: the replacement of some text betweeen some columns
177cef8759bSmrg on the line.
178cef8759bSmrg
179cef8759bSmrg Subsequent events will need their columns adjusting if they're
180cef8759bSmrg are on this line and their column is >= the start point. */
1813ad841b2Smrg
1823ad841b2Smrg class line_event
1833ad841b2Smrg {
1843ad841b2Smrg public:
line_event(int start,int next,int len)185cef8759bSmrg line_event (int start, int next, int len) : m_start (start),
186627f7eb2Smrg m_delta (len - (next - start)) {}
1873ad841b2Smrg
get_effective_column(int orig_column)188cef8759bSmrg int get_effective_column (int orig_column) const
1893ad841b2Smrg {
1903ad841b2Smrg if (orig_column >= m_start)
1913ad841b2Smrg return orig_column += m_delta;
1923ad841b2Smrg else
1933ad841b2Smrg return orig_column;
1943ad841b2Smrg }
1953ad841b2Smrg
1963ad841b2Smrg private:
1973ad841b2Smrg int m_start;
1983ad841b2Smrg int m_delta;
1993ad841b2Smrg };
2003ad841b2Smrg
201cef8759bSmrg /* Forward decls. */
202cef8759bSmrg
203cef8759bSmrg static void
204cef8759bSmrg print_diff_line (pretty_printer *pp, char prefix_char,
205cef8759bSmrg const char *line, int line_size);
206cef8759bSmrg
2073ad841b2Smrg /* Implementation of class edit_context. */
2083ad841b2Smrg
2093ad841b2Smrg /* edit_context's ctor. */
2103ad841b2Smrg
edit_context()2113ad841b2Smrg edit_context::edit_context ()
2123ad841b2Smrg : m_valid (true),
2133ad841b2Smrg m_files (strcmp, NULL, edited_file::delete_cb)
2143ad841b2Smrg {}
2153ad841b2Smrg
2163ad841b2Smrg /* Add any fixits within RICHLOC to this context, recording the
2173ad841b2Smrg changes that they make. */
2183ad841b2Smrg
2193ad841b2Smrg void
add_fixits(rich_location * richloc)2203ad841b2Smrg edit_context::add_fixits (rich_location *richloc)
2213ad841b2Smrg {
2223ad841b2Smrg if (!m_valid)
2233ad841b2Smrg return;
2243ad841b2Smrg if (richloc->seen_impossible_fixit_p ())
2253ad841b2Smrg {
2263ad841b2Smrg m_valid = false;
2273ad841b2Smrg return;
2283ad841b2Smrg }
2293ad841b2Smrg for (unsigned i = 0; i < richloc->get_num_fixit_hints (); i++)
2303ad841b2Smrg {
2313ad841b2Smrg const fixit_hint *hint = richloc->get_fixit_hint (i);
232cef8759bSmrg if (!apply_fixit (hint))
2333ad841b2Smrg m_valid = false;
2343ad841b2Smrg }
2353ad841b2Smrg }
2363ad841b2Smrg
2373ad841b2Smrg /* Get the content of the given file, with fix-its applied.
2383ad841b2Smrg If any errors occurred in this edit_context, return NULL.
2393ad841b2Smrg The ptr should be freed by the caller. */
2403ad841b2Smrg
2413ad841b2Smrg char *
get_content(const char * filename)2423ad841b2Smrg edit_context::get_content (const char *filename)
2433ad841b2Smrg {
2443ad841b2Smrg if (!m_valid)
2453ad841b2Smrg return NULL;
2463ad841b2Smrg edited_file &file = get_or_insert_file (filename);
2473ad841b2Smrg return file.get_content ();
2483ad841b2Smrg }
2493ad841b2Smrg
2503ad841b2Smrg /* Map a location before the edits to a column number after the edits.
2513ad841b2Smrg This method is for the selftests. */
2523ad841b2Smrg
2533ad841b2Smrg int
get_effective_column(const char * filename,int line,int column)2543ad841b2Smrg edit_context::get_effective_column (const char *filename, int line,
2553ad841b2Smrg int column)
2563ad841b2Smrg {
2573ad841b2Smrg edited_file *file = get_file (filename);
2583ad841b2Smrg if (!file)
2593ad841b2Smrg return column;
2603ad841b2Smrg return file->get_effective_column (line, column);
2613ad841b2Smrg }
2623ad841b2Smrg
2633ad841b2Smrg /* Generate a unified diff. The resulting string should be freed by the
2643ad841b2Smrg caller. Primarily for selftests.
2653ad841b2Smrg If any errors occurred in this edit_context, return NULL. */
2663ad841b2Smrg
2673ad841b2Smrg char *
generate_diff(bool show_filenames)2683ad841b2Smrg edit_context::generate_diff (bool show_filenames)
2693ad841b2Smrg {
2703ad841b2Smrg if (!m_valid)
2713ad841b2Smrg return NULL;
2723ad841b2Smrg
2733ad841b2Smrg pretty_printer pp;
2743ad841b2Smrg print_diff (&pp, show_filenames);
2753ad841b2Smrg return xstrdup (pp_formatted_text (&pp));
2763ad841b2Smrg }
2773ad841b2Smrg
2783ad841b2Smrg /* Print a unified diff to PP, showing the changes made within the
2793ad841b2Smrg context. */
2803ad841b2Smrg
2813ad841b2Smrg void
print_diff(pretty_printer * pp,bool show_filenames)2823ad841b2Smrg edit_context::print_diff (pretty_printer *pp, bool show_filenames)
2833ad841b2Smrg {
2843ad841b2Smrg if (!m_valid)
2853ad841b2Smrg return;
2863ad841b2Smrg diff d (pp, show_filenames);
2873ad841b2Smrg m_files.foreach (edited_file::call_print_diff, &d);
2883ad841b2Smrg }
2893ad841b2Smrg
2903ad841b2Smrg /* Attempt to apply the given fixit. Return true if it can be
2913ad841b2Smrg applied, or false otherwise. */
2923ad841b2Smrg
2933ad841b2Smrg bool
apply_fixit(const fixit_hint * hint)294cef8759bSmrg edit_context::apply_fixit (const fixit_hint *hint)
2953ad841b2Smrg {
296cef8759bSmrg expanded_location start = expand_location (hint->get_start_loc ());
297cef8759bSmrg expanded_location next_loc = expand_location (hint->get_next_loc ());
298cef8759bSmrg if (start.file != next_loc.file)
2993ad841b2Smrg return false;
300cef8759bSmrg if (start.line != next_loc.line)
3013ad841b2Smrg return false;
3023ad841b2Smrg if (start.column == 0)
3033ad841b2Smrg return false;
304cef8759bSmrg if (next_loc.column == 0)
3053ad841b2Smrg return false;
3063ad841b2Smrg
3073ad841b2Smrg edited_file &file = get_or_insert_file (start.file);
3083ad841b2Smrg if (!m_valid)
3093ad841b2Smrg return false;
310cef8759bSmrg return file.apply_fixit (start.line, start.column, next_loc.column,
311cef8759bSmrg hint->get_string (),
312cef8759bSmrg hint->get_length ());
3133ad841b2Smrg }
3143ad841b2Smrg
3153ad841b2Smrg /* Locate the edited_file * for FILENAME, if any
3163ad841b2Smrg Return NULL if there isn't one. */
3173ad841b2Smrg
3183ad841b2Smrg edited_file *
get_file(const char * filename)3193ad841b2Smrg edit_context::get_file (const char *filename)
3203ad841b2Smrg {
3213ad841b2Smrg gcc_assert (filename);
3223ad841b2Smrg return m_files.lookup (filename);
3233ad841b2Smrg }
3243ad841b2Smrg
3253ad841b2Smrg /* Locate the edited_file for FILENAME, adding one if there isn't one. */
3263ad841b2Smrg
3273ad841b2Smrg edited_file &
get_or_insert_file(const char * filename)3283ad841b2Smrg edit_context::get_or_insert_file (const char *filename)
3293ad841b2Smrg {
3303ad841b2Smrg gcc_assert (filename);
3313ad841b2Smrg
3323ad841b2Smrg edited_file *file = get_file (filename);
3333ad841b2Smrg if (file)
3343ad841b2Smrg return *file;
3353ad841b2Smrg
3363ad841b2Smrg /* Not found. */
3373ad841b2Smrg file = new edited_file (filename);
3383ad841b2Smrg m_files.insert (filename, file);
3393ad841b2Smrg return *file;
3403ad841b2Smrg }
3413ad841b2Smrg
3423ad841b2Smrg /* Implementation of class edited_file. */
3433ad841b2Smrg
3443ad841b2Smrg /* Callback for m_edited_lines, for comparing line numbers. */
3453ad841b2Smrg
line_comparator(int a,int b)3463ad841b2Smrg static int line_comparator (int a, int b)
3473ad841b2Smrg {
3483ad841b2Smrg return a - b;
3493ad841b2Smrg }
3503ad841b2Smrg
3513ad841b2Smrg /* edited_file's constructor. */
3523ad841b2Smrg
edited_file(const char * filename)3533ad841b2Smrg edited_file::edited_file (const char *filename)
3543ad841b2Smrg : m_filename (filename),
3553ad841b2Smrg m_edited_lines (line_comparator, NULL, edited_line::delete_cb),
3563ad841b2Smrg m_num_lines (-1)
3573ad841b2Smrg {
3583ad841b2Smrg }
3593ad841b2Smrg
3603ad841b2Smrg /* A callback for deleting edited_file *, for use as a
3613ad841b2Smrg delete_value_fn for edit_context::m_files. */
3623ad841b2Smrg
3633ad841b2Smrg void
delete_cb(edited_file * file)3643ad841b2Smrg edited_file::delete_cb (edited_file *file)
3653ad841b2Smrg {
3663ad841b2Smrg delete file;
3673ad841b2Smrg }
3683ad841b2Smrg
3693ad841b2Smrg /* Get the content of the file, with fix-its applied.
3703ad841b2Smrg The ptr should be freed by the caller. */
3713ad841b2Smrg
3723ad841b2Smrg char *
get_content()3733ad841b2Smrg edited_file::get_content ()
3743ad841b2Smrg {
3753ad841b2Smrg pretty_printer pp;
3763ad841b2Smrg if (!print_content (&pp))
3773ad841b2Smrg return NULL;
3783ad841b2Smrg return xstrdup (pp_formatted_text (&pp));
3793ad841b2Smrg }
3803ad841b2Smrg
381cef8759bSmrg /* Attempt to replace columns START_COLUMN up to but not including NEXT_COLUMN
382cef8759bSmrg of LINE with the string REPLACEMENT_STR of length REPLACEMENT_LEN,
3833ad841b2Smrg updating the in-memory copy of the line, and the record of edits to
3843ad841b2Smrg the line. */
3853ad841b2Smrg
3863ad841b2Smrg bool
apply_fixit(int line,int start_column,int next_column,const char * replacement_str,int replacement_len)387cef8759bSmrg edited_file::apply_fixit (int line, int start_column, int next_column,
3883ad841b2Smrg const char *replacement_str,
3893ad841b2Smrg int replacement_len)
3903ad841b2Smrg {
3913ad841b2Smrg edited_line *el = get_or_insert_line (line);
3923ad841b2Smrg if (!el)
3933ad841b2Smrg return false;
394cef8759bSmrg return el->apply_fixit (start_column, next_column, replacement_str,
3953ad841b2Smrg replacement_len);
3963ad841b2Smrg }
3973ad841b2Smrg
3983ad841b2Smrg /* Given line LINE, map from COLUMN in the input file to its current
3993ad841b2Smrg column after edits have been applied. */
4003ad841b2Smrg
4013ad841b2Smrg int
get_effective_column(int line,int column)4023ad841b2Smrg edited_file::get_effective_column (int line, int column)
4033ad841b2Smrg {
4043ad841b2Smrg const edited_line *el = get_line (line);
4053ad841b2Smrg if (!el)
4063ad841b2Smrg return column;
4073ad841b2Smrg return el->get_effective_column (column);
4083ad841b2Smrg }
4093ad841b2Smrg
4103ad841b2Smrg /* Attempt to print the content of the file to PP, with edits applied.
4113ad841b2Smrg Return true if successful, false otherwise. */
4123ad841b2Smrg
4133ad841b2Smrg bool
print_content(pretty_printer * pp)4143ad841b2Smrg edited_file::print_content (pretty_printer *pp)
4153ad841b2Smrg {
4163ad841b2Smrg bool missing_trailing_newline;
4173ad841b2Smrg int line_count = get_num_lines (&missing_trailing_newline);
4183ad841b2Smrg for (int line_num = 1; line_num <= line_count; line_num++)
4193ad841b2Smrg {
4203ad841b2Smrg edited_line *el = get_line (line_num);
4213ad841b2Smrg if (el)
422cef8759bSmrg el->print_content (pp);
4233ad841b2Smrg else
4243ad841b2Smrg {
425627f7eb2Smrg char_span line = location_get_source_line (m_filename, line_num);
4263ad841b2Smrg if (!line)
4273ad841b2Smrg return false;
428627f7eb2Smrg for (size_t i = 0; i < line.length (); i++)
4293ad841b2Smrg pp_character (pp, line[i]);
4303ad841b2Smrg }
4313ad841b2Smrg if (line_num < line_count)
4323ad841b2Smrg pp_character (pp, '\n');
4333ad841b2Smrg }
4343ad841b2Smrg
4353ad841b2Smrg if (!missing_trailing_newline)
4363ad841b2Smrg pp_character (pp, '\n');
4373ad841b2Smrg
4383ad841b2Smrg return true;
4393ad841b2Smrg }
4403ad841b2Smrg
4413ad841b2Smrg /* Print a unified diff to PP, showing any changes that have occurred
4423ad841b2Smrg to this file. */
4433ad841b2Smrg
4443ad841b2Smrg void
print_diff(pretty_printer * pp,bool show_filenames)4453ad841b2Smrg edited_file::print_diff (pretty_printer *pp, bool show_filenames)
4463ad841b2Smrg {
4473ad841b2Smrg if (show_filenames)
4483ad841b2Smrg {
4493ad841b2Smrg pp_string (pp, colorize_start (pp_show_color (pp), "diff-filename"));
4503ad841b2Smrg pp_printf (pp, "--- %s\n", m_filename);
4513ad841b2Smrg pp_printf (pp, "+++ %s\n", m_filename);
4523ad841b2Smrg pp_string (pp, colorize_stop (pp_show_color (pp)));
4533ad841b2Smrg }
4543ad841b2Smrg
4553ad841b2Smrg edited_line *el = m_edited_lines.min ();
4563ad841b2Smrg
4573ad841b2Smrg bool missing_trailing_newline;
4583ad841b2Smrg int line_count = get_num_lines (&missing_trailing_newline);
4593ad841b2Smrg
4603ad841b2Smrg const int context_lines = 3;
4613ad841b2Smrg
462cef8759bSmrg /* Track new line numbers minus old line numbers. */
463cef8759bSmrg
464cef8759bSmrg int line_delta = 0;
465cef8759bSmrg
4663ad841b2Smrg while (el)
4673ad841b2Smrg {
4683ad841b2Smrg int start_of_hunk = el->get_line_num ();
4693ad841b2Smrg start_of_hunk -= context_lines;
4703ad841b2Smrg if (start_of_hunk < 1)
4713ad841b2Smrg start_of_hunk = 1;
4723ad841b2Smrg
4733ad841b2Smrg /* Locate end of hunk, merging in changed lines
4743ad841b2Smrg that are sufficiently close. */
4753ad841b2Smrg while (true)
4763ad841b2Smrg {
4773ad841b2Smrg edited_line *next_el
4783ad841b2Smrg = m_edited_lines.successor (el->get_line_num ());
4793ad841b2Smrg if (!next_el)
4803ad841b2Smrg break;
481cef8759bSmrg
482cef8759bSmrg int end_of_printed_hunk = el->get_line_num () + context_lines;
483cef8759bSmrg if (!el->actually_edited_p ())
484cef8759bSmrg end_of_printed_hunk--;
485cef8759bSmrg
486cef8759bSmrg if (end_of_printed_hunk
4873ad841b2Smrg >= next_el->get_line_num () - context_lines)
4883ad841b2Smrg el = next_el;
4893ad841b2Smrg else
4903ad841b2Smrg break;
4913ad841b2Smrg }
492cef8759bSmrg
4933ad841b2Smrg int end_of_hunk = el->get_line_num ();
4943ad841b2Smrg end_of_hunk += context_lines;
495cef8759bSmrg if (!el->actually_edited_p ())
496cef8759bSmrg end_of_hunk--;
4973ad841b2Smrg if (end_of_hunk > line_count)
4983ad841b2Smrg end_of_hunk = line_count;
4993ad841b2Smrg
500cef8759bSmrg int new_start_of_hunk = start_of_hunk + line_delta;
501cef8759bSmrg line_delta += print_diff_hunk (pp, start_of_hunk, end_of_hunk,
502cef8759bSmrg new_start_of_hunk);
5033ad841b2Smrg el = m_edited_lines.successor (el->get_line_num ());
5043ad841b2Smrg }
5053ad841b2Smrg }
5063ad841b2Smrg
5073ad841b2Smrg /* Print one hunk within a unified diff to PP, covering the
508cef8759bSmrg given range of lines. OLD_START_OF_HUNK and OLD_END_OF_HUNK are
509cef8759bSmrg line numbers in the unedited version of the file.
510cef8759bSmrg NEW_START_OF_HUNK is a line number in the edited version of the file.
511cef8759bSmrg Return the change in the line count within the hunk. */
5123ad841b2Smrg
513cef8759bSmrg int
print_diff_hunk(pretty_printer * pp,int old_start_of_hunk,int old_end_of_hunk,int new_start_of_hunk)514cef8759bSmrg edited_file::print_diff_hunk (pretty_printer *pp, int old_start_of_hunk,
515cef8759bSmrg int old_end_of_hunk, int new_start_of_hunk)
5163ad841b2Smrg {
517cef8759bSmrg int old_num_lines = old_end_of_hunk - old_start_of_hunk + 1;
518cef8759bSmrg int new_num_lines
519cef8759bSmrg = get_effective_line_count (old_start_of_hunk, old_end_of_hunk);
5203ad841b2Smrg
5213ad841b2Smrg pp_string (pp, colorize_start (pp_show_color (pp), "diff-hunk"));
522cef8759bSmrg pp_printf (pp, "@@ -%i,%i +%i,%i @@\n", old_start_of_hunk, old_num_lines,
523cef8759bSmrg new_start_of_hunk, new_num_lines);
5243ad841b2Smrg pp_string (pp, colorize_stop (pp_show_color (pp)));
5253ad841b2Smrg
526cef8759bSmrg int line_num = old_start_of_hunk;
527cef8759bSmrg while (line_num <= old_end_of_hunk)
5283ad841b2Smrg {
5293ad841b2Smrg edited_line *el = get_line (line_num);
5303ad841b2Smrg if (el)
5313ad841b2Smrg {
5323ad841b2Smrg /* We have an edited line.
5333ad841b2Smrg Consolidate into runs of changed lines. */
5343ad841b2Smrg const int first_changed_line_in_run = line_num;
5353ad841b2Smrg while (get_line (line_num))
5363ad841b2Smrg line_num++;
5373ad841b2Smrg const int last_changed_line_in_run = line_num - 1;
538cef8759bSmrg print_run_of_changed_lines (pp, first_changed_line_in_run,
539cef8759bSmrg last_changed_line_in_run);
5403ad841b2Smrg }
5413ad841b2Smrg else
5423ad841b2Smrg {
5433ad841b2Smrg /* Unchanged line. */
544627f7eb2Smrg char_span old_line = location_get_source_line (m_filename, line_num);
545627f7eb2Smrg print_diff_line (pp, ' ', old_line.get_buffer (), old_line.length ());
5463ad841b2Smrg line_num++;
5473ad841b2Smrg }
5483ad841b2Smrg }
549cef8759bSmrg
550cef8759bSmrg return new_num_lines - old_num_lines;
551cef8759bSmrg }
552cef8759bSmrg
553cef8759bSmrg /* Subroutine of edited_file::print_diff_hunk: given a run of lines
554cef8759bSmrg from START_OF_RUN to END_OF_RUN that all have edited_line instances,
555cef8759bSmrg print the diff to PP. */
556cef8759bSmrg
557cef8759bSmrg void
print_run_of_changed_lines(pretty_printer * pp,int start_of_run,int end_of_run)558cef8759bSmrg edited_file::print_run_of_changed_lines (pretty_printer *pp,
559cef8759bSmrg int start_of_run,
560cef8759bSmrg int end_of_run)
561cef8759bSmrg {
562cef8759bSmrg /* Show old version of lines. */
563cef8759bSmrg pp_string (pp, colorize_start (pp_show_color (pp),
564cef8759bSmrg "diff-delete"));
565cef8759bSmrg for (int line_num = start_of_run;
566cef8759bSmrg line_num <= end_of_run;
567cef8759bSmrg line_num++)
568cef8759bSmrg {
569cef8759bSmrg edited_line *el_in_run = get_line (line_num);
570cef8759bSmrg gcc_assert (el_in_run);
571cef8759bSmrg if (el_in_run->actually_edited_p ())
572cef8759bSmrg {
573627f7eb2Smrg char_span old_line = location_get_source_line (m_filename, line_num);
574627f7eb2Smrg print_diff_line (pp, '-', old_line.get_buffer (),
575627f7eb2Smrg old_line.length ());
576cef8759bSmrg }
577cef8759bSmrg }
578cef8759bSmrg pp_string (pp, colorize_stop (pp_show_color (pp)));
579cef8759bSmrg
580cef8759bSmrg /* Show new version of lines. */
581cef8759bSmrg pp_string (pp, colorize_start (pp_show_color (pp),
582cef8759bSmrg "diff-insert"));
583cef8759bSmrg for (int line_num = start_of_run;
584cef8759bSmrg line_num <= end_of_run;
585cef8759bSmrg line_num++)
586cef8759bSmrg {
587cef8759bSmrg edited_line *el_in_run = get_line (line_num);
588cef8759bSmrg gcc_assert (el_in_run);
589cef8759bSmrg el_in_run->print_diff_lines (pp);
590cef8759bSmrg }
591cef8759bSmrg pp_string (pp, colorize_stop (pp_show_color (pp)));
5923ad841b2Smrg }
5933ad841b2Smrg
5943ad841b2Smrg /* Print one line within a diff, starting with PREFIX_CHAR,
5953ad841b2Smrg followed by the LINE of content, of length LEN. LINE is
5963ad841b2Smrg not necessarily 0-terminated. Print a trailing newline. */
5973ad841b2Smrg
598cef8759bSmrg static void
print_diff_line(pretty_printer * pp,char prefix_char,const char * line,int len)599cef8759bSmrg print_diff_line (pretty_printer *pp, char prefix_char,
6003ad841b2Smrg const char *line, int len)
6013ad841b2Smrg {
6023ad841b2Smrg pp_character (pp, prefix_char);
6033ad841b2Smrg for (int i = 0; i < len; i++)
6043ad841b2Smrg pp_character (pp, line[i]);
6053ad841b2Smrg pp_character (pp, '\n');
6063ad841b2Smrg }
6073ad841b2Smrg
608cef8759bSmrg /* Determine the number of lines that will be present after
609cef8759bSmrg editing for the range of lines from OLD_START_OF_HUNK to
610cef8759bSmrg OLD_END_OF_HUNK inclusive. */
611cef8759bSmrg
612cef8759bSmrg int
get_effective_line_count(int old_start_of_hunk,int old_end_of_hunk)613cef8759bSmrg edited_file::get_effective_line_count (int old_start_of_hunk,
614cef8759bSmrg int old_end_of_hunk)
615cef8759bSmrg {
616cef8759bSmrg int line_count = 0;
617cef8759bSmrg for (int old_line_num = old_start_of_hunk; old_line_num <= old_end_of_hunk;
618cef8759bSmrg old_line_num++)
619cef8759bSmrg {
620cef8759bSmrg edited_line *el = get_line (old_line_num);
621cef8759bSmrg if (el)
622cef8759bSmrg line_count += el->get_effective_line_count ();
623cef8759bSmrg else
624cef8759bSmrg line_count++;
625cef8759bSmrg }
626cef8759bSmrg return line_count;
627cef8759bSmrg }
628cef8759bSmrg
6293ad841b2Smrg /* Get the state of LINE within the file, or NULL if it is untouched. */
6303ad841b2Smrg
6313ad841b2Smrg edited_line *
get_line(int line)6323ad841b2Smrg edited_file::get_line (int line)
6333ad841b2Smrg {
6343ad841b2Smrg return m_edited_lines.lookup (line);
6353ad841b2Smrg }
6363ad841b2Smrg
6373ad841b2Smrg /* Get the state of LINE within the file, creating a state for it
6383ad841b2Smrg if necessary. Return NULL if an error occurs. */
6393ad841b2Smrg
6403ad841b2Smrg edited_line *
get_or_insert_line(int line)6413ad841b2Smrg edited_file::get_or_insert_line (int line)
6423ad841b2Smrg {
6433ad841b2Smrg edited_line *el = get_line (line);
6443ad841b2Smrg if (el)
6453ad841b2Smrg return el;
6463ad841b2Smrg el = new edited_line (m_filename, line);
6473ad841b2Smrg if (el->get_content () == NULL)
6483ad841b2Smrg {
6493ad841b2Smrg delete el;
6503ad841b2Smrg return NULL;
6513ad841b2Smrg }
6523ad841b2Smrg m_edited_lines.insert (line, el);
6533ad841b2Smrg return el;
6543ad841b2Smrg }
6553ad841b2Smrg
6563ad841b2Smrg /* Get the total number of lines in m_content, writing
6573ad841b2Smrg true to *MISSING_TRAILING_NEWLINE if the final line
6583ad841b2Smrg if missing a newline, false otherwise. */
6593ad841b2Smrg
6603ad841b2Smrg int
get_num_lines(bool * missing_trailing_newline)6613ad841b2Smrg edited_file::get_num_lines (bool *missing_trailing_newline)
6623ad841b2Smrg {
6633ad841b2Smrg gcc_assert (missing_trailing_newline);
6643ad841b2Smrg if (m_num_lines == -1)
6653ad841b2Smrg {
6663ad841b2Smrg m_num_lines = 0;
6673ad841b2Smrg while (true)
6683ad841b2Smrg {
669627f7eb2Smrg char_span line
670627f7eb2Smrg = location_get_source_line (m_filename, m_num_lines + 1);
6713ad841b2Smrg if (line)
6723ad841b2Smrg m_num_lines++;
6733ad841b2Smrg else
6743ad841b2Smrg break;
6753ad841b2Smrg }
6763ad841b2Smrg }
6773ad841b2Smrg *missing_trailing_newline = location_missing_trailing_newline (m_filename);
6783ad841b2Smrg return m_num_lines;
6793ad841b2Smrg }
6803ad841b2Smrg
6813ad841b2Smrg /* Implementation of class edited_line. */
6823ad841b2Smrg
6833ad841b2Smrg /* edited_line's ctor. */
6843ad841b2Smrg
edited_line(const char * filename,int line_num)6853ad841b2Smrg edited_line::edited_line (const char *filename, int line_num)
6863ad841b2Smrg : m_line_num (line_num),
6873ad841b2Smrg m_content (NULL), m_len (0), m_alloc_sz (0),
688cef8759bSmrg m_line_events (),
689cef8759bSmrg m_predecessors ()
6903ad841b2Smrg {
691627f7eb2Smrg char_span line = location_get_source_line (filename, line_num);
6923ad841b2Smrg if (!line)
6933ad841b2Smrg return;
694627f7eb2Smrg m_len = line.length ();
6953ad841b2Smrg ensure_capacity (m_len);
696627f7eb2Smrg memcpy (m_content, line.get_buffer (), m_len);
6973ad841b2Smrg ensure_terminated ();
6983ad841b2Smrg }
6993ad841b2Smrg
7003ad841b2Smrg /* edited_line's dtor. */
7013ad841b2Smrg
~edited_line()7023ad841b2Smrg edited_line::~edited_line ()
7033ad841b2Smrg {
704cef8759bSmrg unsigned i;
705cef8759bSmrg added_line *pred;
7063ad841b2Smrg
707cef8759bSmrg free (m_content);
708cef8759bSmrg FOR_EACH_VEC_ELT (m_predecessors, i, pred)
709cef8759bSmrg delete pred;
7103ad841b2Smrg }
7113ad841b2Smrg
7123ad841b2Smrg /* A callback for deleting edited_line *, for use as a
7133ad841b2Smrg delete_value_fn for edited_file::m_edited_lines. */
7143ad841b2Smrg
7153ad841b2Smrg void
delete_cb(edited_line * el)7163ad841b2Smrg edited_line::delete_cb (edited_line *el)
7173ad841b2Smrg {
7183ad841b2Smrg delete el;
7193ad841b2Smrg }
7203ad841b2Smrg
7213ad841b2Smrg /* Map a location before the edits to a column number after the edits,
7223ad841b2Smrg within a specific line. */
7233ad841b2Smrg
7243ad841b2Smrg int
get_effective_column(int orig_column)7253ad841b2Smrg edited_line::get_effective_column (int orig_column) const
7263ad841b2Smrg {
7273ad841b2Smrg int i;
7283ad841b2Smrg line_event *event;
7293ad841b2Smrg FOR_EACH_VEC_ELT (m_line_events, i, event)
7303ad841b2Smrg orig_column = event->get_effective_column (orig_column);
7313ad841b2Smrg return orig_column;
7323ad841b2Smrg }
7333ad841b2Smrg
734cef8759bSmrg /* Attempt to replace columns START_COLUMN up to but not including
735cef8759bSmrg NEXT_COLUMN of the line with the string REPLACEMENT_STR of
736cef8759bSmrg length REPLACEMENT_LEN, updating the in-memory copy of the line,
737cef8759bSmrg and the record of edits to the line.
7383ad841b2Smrg Return true if successful; false if an error occurred. */
7393ad841b2Smrg
7403ad841b2Smrg bool
apply_fixit(int start_column,int next_column,const char * replacement_str,int replacement_len)741cef8759bSmrg edited_line::apply_fixit (int start_column,
742cef8759bSmrg int next_column,
7433ad841b2Smrg const char *replacement_str,
7443ad841b2Smrg int replacement_len)
7453ad841b2Smrg {
746cef8759bSmrg /* Handle newlines. They will only ever be at the end of the
747cef8759bSmrg replacement text, thanks to the filtering in rich_location. */
748cef8759bSmrg if (replacement_len > 1)
749cef8759bSmrg if (replacement_str[replacement_len - 1] == '\n')
750cef8759bSmrg {
751cef8759bSmrg /* Stash in m_predecessors, stripping off newline. */
752cef8759bSmrg m_predecessors.safe_push (new added_line (replacement_str,
753cef8759bSmrg replacement_len - 1));
754cef8759bSmrg return true;
755cef8759bSmrg }
756cef8759bSmrg
7573ad841b2Smrg start_column = get_effective_column (start_column);
758cef8759bSmrg next_column = get_effective_column (next_column);
7593ad841b2Smrg
7603ad841b2Smrg int start_offset = start_column - 1;
761cef8759bSmrg int next_offset = next_column - 1;
7623ad841b2Smrg
7633ad841b2Smrg gcc_assert (start_offset >= 0);
764cef8759bSmrg gcc_assert (next_offset >= 0);
7653ad841b2Smrg
766cef8759bSmrg if (start_column > next_column)
7673ad841b2Smrg return false;
768cef8759bSmrg if (start_offset >= (m_len + 1))
7693ad841b2Smrg return false;
770cef8759bSmrg if (next_offset >= (m_len + 1))
7713ad841b2Smrg return false;
7723ad841b2Smrg
773cef8759bSmrg size_t victim_len = next_offset - start_offset;
7743ad841b2Smrg
7753ad841b2Smrg /* Ensure buffer is big enough. */
7763ad841b2Smrg size_t new_len = m_len + replacement_len - victim_len;
7773ad841b2Smrg ensure_capacity (new_len);
7783ad841b2Smrg
779cef8759bSmrg char *suffix = m_content + next_offset;
7803ad841b2Smrg gcc_assert (suffix <= m_content + m_len);
7813ad841b2Smrg size_t len_suffix = (m_content + m_len) - suffix;
7823ad841b2Smrg
7833ad841b2Smrg /* Move successor content into position. They overlap, so use memmove. */
7843ad841b2Smrg memmove (m_content + start_offset + replacement_len,
7853ad841b2Smrg suffix, len_suffix);
7863ad841b2Smrg
7873ad841b2Smrg /* Replace target content. They don't overlap, so use memcpy. */
7883ad841b2Smrg memcpy (m_content + start_offset,
7893ad841b2Smrg replacement_str,
7903ad841b2Smrg replacement_len);
7913ad841b2Smrg
7923ad841b2Smrg m_len = new_len;
7933ad841b2Smrg
7943ad841b2Smrg ensure_terminated ();
7953ad841b2Smrg
7963ad841b2Smrg /* Record the replacement, so that future changes to the line can have
7973ad841b2Smrg their column information adjusted accordingly. */
798cef8759bSmrg m_line_events.safe_push (line_event (start_column, next_column,
7993ad841b2Smrg replacement_len));
8003ad841b2Smrg return true;
8013ad841b2Smrg }
8023ad841b2Smrg
803cef8759bSmrg /* Determine the number of lines that will be present after
804cef8759bSmrg editing for this line. Typically this is just 1, but
805cef8759bSmrg if newlines have been added before this line, they will
806cef8759bSmrg also be counted. */
807cef8759bSmrg
808cef8759bSmrg int
get_effective_line_count()809cef8759bSmrg edited_line::get_effective_line_count () const
810cef8759bSmrg {
811cef8759bSmrg return m_predecessors.length () + 1;
812cef8759bSmrg }
813cef8759bSmrg
814cef8759bSmrg /* Subroutine of edited_file::print_content.
815cef8759bSmrg Print this line and any new lines added before it, to PP. */
816cef8759bSmrg
817cef8759bSmrg void
print_content(pretty_printer * pp)818cef8759bSmrg edited_line::print_content (pretty_printer *pp) const
819cef8759bSmrg {
820cef8759bSmrg unsigned i;
821cef8759bSmrg added_line *pred;
822cef8759bSmrg FOR_EACH_VEC_ELT (m_predecessors, i, pred)
823cef8759bSmrg {
824cef8759bSmrg pp_string (pp, pred->get_content ());
825cef8759bSmrg pp_newline (pp);
826cef8759bSmrg }
827cef8759bSmrg pp_string (pp, m_content);
828cef8759bSmrg }
829cef8759bSmrg
830cef8759bSmrg /* Subroutine of edited_file::print_run_of_changed_lines for
831cef8759bSmrg printing diff hunks to PP.
832cef8759bSmrg Print the '+' line for this line, and any newlines added
833cef8759bSmrg before it.
834cef8759bSmrg Note that if this edited_line was actually edited, the '-'
835cef8759bSmrg line has already been printed. If it wasn't, then we merely
836cef8759bSmrg have a placeholder edited_line for adding newlines to, and
837cef8759bSmrg we need to print a ' ' line for the edited_line as we haven't
838cef8759bSmrg printed it yet. */
839cef8759bSmrg
840cef8759bSmrg void
print_diff_lines(pretty_printer * pp)841cef8759bSmrg edited_line::print_diff_lines (pretty_printer *pp) const
842cef8759bSmrg {
843cef8759bSmrg unsigned i;
844cef8759bSmrg added_line *pred;
845cef8759bSmrg FOR_EACH_VEC_ELT (m_predecessors, i, pred)
846cef8759bSmrg print_diff_line (pp, '+', pred->get_content (),
847cef8759bSmrg pred->get_len ());
848cef8759bSmrg if (actually_edited_p ())
849cef8759bSmrg print_diff_line (pp, '+', m_content, m_len);
850cef8759bSmrg else
851cef8759bSmrg print_diff_line (pp, ' ', m_content, m_len);
852cef8759bSmrg }
853cef8759bSmrg
8543ad841b2Smrg /* Ensure that the buffer for m_content is at least large enough to hold
8553ad841b2Smrg a string of length LEN and its 0-terminator, doubling on repeated
8563ad841b2Smrg allocations. */
8573ad841b2Smrg
8583ad841b2Smrg void
ensure_capacity(int len)8593ad841b2Smrg edited_line::ensure_capacity (int len)
8603ad841b2Smrg {
8613ad841b2Smrg /* Allow 1 extra byte for 0-termination. */
8623ad841b2Smrg if (m_alloc_sz < (len + 1))
8633ad841b2Smrg {
8643ad841b2Smrg size_t new_alloc_sz = (len + 1) * 2;
8653ad841b2Smrg m_content = (char *)xrealloc (m_content, new_alloc_sz);
8663ad841b2Smrg m_alloc_sz = new_alloc_sz;
8673ad841b2Smrg }
8683ad841b2Smrg }
8693ad841b2Smrg
8703ad841b2Smrg /* Ensure that m_content is 0-terminated. */
8713ad841b2Smrg
8723ad841b2Smrg void
ensure_terminated()8733ad841b2Smrg edited_line::ensure_terminated ()
8743ad841b2Smrg {
8753ad841b2Smrg /* 0-terminate the buffer. */
8763ad841b2Smrg gcc_assert (m_len < m_alloc_sz);
8773ad841b2Smrg m_content[m_len] = '\0';
8783ad841b2Smrg }
8793ad841b2Smrg
8803ad841b2Smrg #if CHECKING_P
8813ad841b2Smrg
8823ad841b2Smrg /* Selftests of code-editing. */
8833ad841b2Smrg
8843ad841b2Smrg namespace selftest {
8853ad841b2Smrg
8863ad841b2Smrg /* A wrapper class for ensuring that the underlying pointer is freed. */
8873ad841b2Smrg
8883ad841b2Smrg template <typename POINTER_T>
8893ad841b2Smrg class auto_free
8903ad841b2Smrg {
8913ad841b2Smrg public:
auto_free(POINTER_T p)8923ad841b2Smrg auto_free (POINTER_T p) : m_ptr (p) {}
~auto_free()8933ad841b2Smrg ~auto_free () { free (m_ptr); }
8943ad841b2Smrg
POINTER_T()8953ad841b2Smrg operator POINTER_T () { return m_ptr; }
8963ad841b2Smrg
8973ad841b2Smrg private:
8983ad841b2Smrg POINTER_T m_ptr;
8993ad841b2Smrg };
9003ad841b2Smrg
9013ad841b2Smrg /* Verify that edit_context::get_content works for unedited files. */
9023ad841b2Smrg
9033ad841b2Smrg static void
test_get_content()9043ad841b2Smrg test_get_content ()
9053ad841b2Smrg {
9063ad841b2Smrg /* Test of empty file. */
9073ad841b2Smrg {
9083ad841b2Smrg const char *content = ("");
9093ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
9103ad841b2Smrg edit_context edit;
9113ad841b2Smrg auto_free <char *> result = edit.get_content (tmp.get_filename ());
9123ad841b2Smrg ASSERT_STREQ ("", result);
9133ad841b2Smrg }
9143ad841b2Smrg
9153ad841b2Smrg /* Test of simple content. */
9163ad841b2Smrg {
9173ad841b2Smrg const char *content = ("/* before */\n"
9183ad841b2Smrg "foo = bar.field;\n"
9193ad841b2Smrg "/* after */\n");
9203ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
9213ad841b2Smrg edit_context edit;
9223ad841b2Smrg auto_free <char *> result = edit.get_content (tmp.get_filename ());
9233ad841b2Smrg ASSERT_STREQ ("/* before */\n"
9243ad841b2Smrg "foo = bar.field;\n"
9253ad841b2Smrg "/* after */\n", result);
9263ad841b2Smrg }
9273ad841b2Smrg
9283ad841b2Smrg /* Test of omitting the trailing newline on the final line. */
9293ad841b2Smrg {
9303ad841b2Smrg const char *content = ("/* before */\n"
9313ad841b2Smrg "foo = bar.field;\n"
9323ad841b2Smrg "/* after */");
9333ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
9343ad841b2Smrg edit_context edit;
9353ad841b2Smrg auto_free <char *> result = edit.get_content (tmp.get_filename ());
9363ad841b2Smrg /* We should respect the omitted trailing newline. */
9373ad841b2Smrg ASSERT_STREQ ("/* before */\n"
9383ad841b2Smrg "foo = bar.field;\n"
9393ad841b2Smrg "/* after */", result);
9403ad841b2Smrg }
9413ad841b2Smrg }
9423ad841b2Smrg
9433ad841b2Smrg /* Test applying an "insert" fixit, using insert_before. */
9443ad841b2Smrg
9453ad841b2Smrg static void
test_applying_fixits_insert_before(const line_table_case & case_)9463ad841b2Smrg test_applying_fixits_insert_before (const line_table_case &case_)
9473ad841b2Smrg {
9483ad841b2Smrg /* Create a tempfile and write some text to it.
9493ad841b2Smrg .........................0000000001111111.
9503ad841b2Smrg .........................1234567890123456. */
9513ad841b2Smrg const char *old_content = ("/* before */\n"
9523ad841b2Smrg "foo = bar.field;\n"
9533ad841b2Smrg "/* after */\n");
9543ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
9553ad841b2Smrg const char *filename = tmp.get_filename ();
9563ad841b2Smrg line_table_test ltt (case_);
9573ad841b2Smrg linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 2);
9583ad841b2Smrg
9593ad841b2Smrg /* Add a comment in front of "bar.field". */
9603ad841b2Smrg location_t start = linemap_position_for_column (line_table, 7);
9613ad841b2Smrg rich_location richloc (line_table, start);
9623ad841b2Smrg richloc.add_fixit_insert_before ("/* inserted */");
9633ad841b2Smrg
9643ad841b2Smrg if (start > LINE_MAP_MAX_LOCATION_WITH_COLS)
9653ad841b2Smrg return;
9663ad841b2Smrg
9673ad841b2Smrg edit_context edit;
9683ad841b2Smrg edit.add_fixits (&richloc);
9693ad841b2Smrg auto_free <char *> new_content = edit.get_content (filename);
9703ad841b2Smrg if (start <= LINE_MAP_MAX_LOCATION_WITH_COLS)
9713ad841b2Smrg ASSERT_STREQ ("/* before */\n"
9723ad841b2Smrg "foo = /* inserted */bar.field;\n"
9733ad841b2Smrg "/* after */\n", new_content);
9743ad841b2Smrg
9753ad841b2Smrg /* Verify that locations on other lines aren't affected by the change. */
9763ad841b2Smrg ASSERT_EQ (100, edit.get_effective_column (filename, 1, 100));
9773ad841b2Smrg ASSERT_EQ (100, edit.get_effective_column (filename, 3, 100));
9783ad841b2Smrg
9793ad841b2Smrg /* Verify locations on the line before the change. */
9803ad841b2Smrg ASSERT_EQ (1, edit.get_effective_column (filename, 2, 1));
9813ad841b2Smrg ASSERT_EQ (6, edit.get_effective_column (filename, 2, 6));
9823ad841b2Smrg
9833ad841b2Smrg /* Verify locations on the line at and after the change. */
9843ad841b2Smrg ASSERT_EQ (21, edit.get_effective_column (filename, 2, 7));
9853ad841b2Smrg ASSERT_EQ (22, edit.get_effective_column (filename, 2, 8));
9863ad841b2Smrg
9873ad841b2Smrg /* Verify diff. */
9883ad841b2Smrg auto_free <char *> diff = edit.generate_diff (false);
9893ad841b2Smrg ASSERT_STREQ ("@@ -1,3 +1,3 @@\n"
9903ad841b2Smrg " /* before */\n"
9913ad841b2Smrg "-foo = bar.field;\n"
9923ad841b2Smrg "+foo = /* inserted */bar.field;\n"
9933ad841b2Smrg " /* after */\n", diff);
9943ad841b2Smrg }
9953ad841b2Smrg
9963ad841b2Smrg /* Test applying an "insert" fixit, using insert_after, with
9973ad841b2Smrg a range of length > 1 (to ensure that the end-point of
9983ad841b2Smrg the input range is used). */
9993ad841b2Smrg
10003ad841b2Smrg static void
test_applying_fixits_insert_after(const line_table_case & case_)10013ad841b2Smrg test_applying_fixits_insert_after (const line_table_case &case_)
10023ad841b2Smrg {
10033ad841b2Smrg /* Create a tempfile and write some text to it.
10043ad841b2Smrg .........................0000000001111111.
10053ad841b2Smrg .........................1234567890123456. */
10063ad841b2Smrg const char *old_content = ("/* before */\n"
10073ad841b2Smrg "foo = bar.field;\n"
10083ad841b2Smrg "/* after */\n");
10093ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
10103ad841b2Smrg const char *filename = tmp.get_filename ();
10113ad841b2Smrg line_table_test ltt (case_);
10123ad841b2Smrg linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 2);
10133ad841b2Smrg
10143ad841b2Smrg /* Add a comment after "field". */
10153ad841b2Smrg location_t start = linemap_position_for_column (line_table, 11);
10163ad841b2Smrg location_t finish = linemap_position_for_column (line_table, 15);
10173ad841b2Smrg location_t field = make_location (start, start, finish);
10183ad841b2Smrg rich_location richloc (line_table, field);
10193ad841b2Smrg richloc.add_fixit_insert_after ("/* inserted */");
10203ad841b2Smrg
10213ad841b2Smrg if (finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
10223ad841b2Smrg return;
10233ad841b2Smrg
10243ad841b2Smrg /* Verify that the text was inserted after the end of "field". */
10253ad841b2Smrg edit_context edit;
10263ad841b2Smrg edit.add_fixits (&richloc);
10273ad841b2Smrg auto_free <char *> new_content = edit.get_content (filename);
10283ad841b2Smrg ASSERT_STREQ ("/* before */\n"
10293ad841b2Smrg "foo = bar.field/* inserted */;\n"
10303ad841b2Smrg "/* after */\n", new_content);
10313ad841b2Smrg
10323ad841b2Smrg /* Verify diff. */
10333ad841b2Smrg auto_free <char *> diff = edit.generate_diff (false);
10343ad841b2Smrg ASSERT_STREQ ("@@ -1,3 +1,3 @@\n"
10353ad841b2Smrg " /* before */\n"
10363ad841b2Smrg "-foo = bar.field;\n"
10373ad841b2Smrg "+foo = bar.field/* inserted */;\n"
10383ad841b2Smrg " /* after */\n", diff);
10393ad841b2Smrg }
10403ad841b2Smrg
10413ad841b2Smrg /* Test applying an "insert" fixit, using insert_after at the end of
10423ad841b2Smrg a line (contrast with test_applying_fixits_insert_after_failure
10433ad841b2Smrg below). */
10443ad841b2Smrg
10453ad841b2Smrg static void
test_applying_fixits_insert_after_at_line_end(const line_table_case & case_)10463ad841b2Smrg test_applying_fixits_insert_after_at_line_end (const line_table_case &case_)
10473ad841b2Smrg {
10483ad841b2Smrg /* Create a tempfile and write some text to it.
10493ad841b2Smrg .........................0000000001111111.
10503ad841b2Smrg .........................1234567890123456. */
10513ad841b2Smrg const char *old_content = ("/* before */\n"
10523ad841b2Smrg "foo = bar.field;\n"
10533ad841b2Smrg "/* after */\n");
10543ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
10553ad841b2Smrg const char *filename = tmp.get_filename ();
10563ad841b2Smrg line_table_test ltt (case_);
10573ad841b2Smrg linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 2);
10583ad841b2Smrg
10593ad841b2Smrg /* Add a comment after the semicolon. */
10603ad841b2Smrg location_t loc = linemap_position_for_column (line_table, 16);
10613ad841b2Smrg rich_location richloc (line_table, loc);
10623ad841b2Smrg richloc.add_fixit_insert_after ("/* inserted */");
10633ad841b2Smrg
10643ad841b2Smrg if (loc > LINE_MAP_MAX_LOCATION_WITH_COLS)
10653ad841b2Smrg return;
10663ad841b2Smrg
10673ad841b2Smrg edit_context edit;
10683ad841b2Smrg edit.add_fixits (&richloc);
10693ad841b2Smrg auto_free <char *> new_content = edit.get_content (filename);
10703ad841b2Smrg ASSERT_STREQ ("/* before */\n"
10713ad841b2Smrg "foo = bar.field;/* inserted */\n"
10723ad841b2Smrg "/* after */\n", new_content);
10733ad841b2Smrg
10743ad841b2Smrg /* Verify diff. */
10753ad841b2Smrg auto_free <char *> diff = edit.generate_diff (false);
10763ad841b2Smrg ASSERT_STREQ ("@@ -1,3 +1,3 @@\n"
10773ad841b2Smrg " /* before */\n"
10783ad841b2Smrg "-foo = bar.field;\n"
10793ad841b2Smrg "+foo = bar.field;/* inserted */\n"
10803ad841b2Smrg " /* after */\n", diff);
10813ad841b2Smrg }
10823ad841b2Smrg
10833ad841b2Smrg /* Test of a failed attempt to apply an "insert" fixit, using insert_after,
10843ad841b2Smrg due to the relevant linemap ending. Contrast with
10853ad841b2Smrg test_applying_fixits_insert_after_at_line_end above. */
10863ad841b2Smrg
10873ad841b2Smrg static void
test_applying_fixits_insert_after_failure(const line_table_case & case_)10883ad841b2Smrg test_applying_fixits_insert_after_failure (const line_table_case &case_)
10893ad841b2Smrg {
10903ad841b2Smrg /* Create a tempfile and write some text to it.
10913ad841b2Smrg .........................0000000001111111.
10923ad841b2Smrg .........................1234567890123456. */
10933ad841b2Smrg const char *old_content = ("/* before */\n"
10943ad841b2Smrg "foo = bar.field;\n"
10953ad841b2Smrg "/* after */\n");
10963ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
10973ad841b2Smrg const char *filename = tmp.get_filename ();
10983ad841b2Smrg line_table_test ltt (case_);
10993ad841b2Smrg linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 2);
11003ad841b2Smrg
11013ad841b2Smrg /* Add a comment after the semicolon. */
11023ad841b2Smrg location_t loc = linemap_position_for_column (line_table, 16);
11033ad841b2Smrg rich_location richloc (line_table, loc);
11043ad841b2Smrg
11053ad841b2Smrg /* We want a failure of linemap_position_for_loc_and_offset.
11063ad841b2Smrg We can do this by starting a new linemap at line 3, so that
11073ad841b2Smrg there is no appropriate location value for the insertion point
11083ad841b2Smrg within the linemap for line 2. */
11093ad841b2Smrg linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 3);
11103ad841b2Smrg
11113ad841b2Smrg /* The failure fails to happen at the transition point from
11123ad841b2Smrg packed ranges to unpacked ranges (where there are some "spare"
11133ad841b2Smrg location_t values). Skip the test there. */
11143ad841b2Smrg if (loc >= LINE_MAP_MAX_LOCATION_WITH_PACKED_RANGES)
11153ad841b2Smrg return;
11163ad841b2Smrg
11173ad841b2Smrg /* Offsetting "loc" should now fail (by returning the input loc. */
11183ad841b2Smrg ASSERT_EQ (loc, linemap_position_for_loc_and_offset (line_table, loc, 1));
11193ad841b2Smrg
11203ad841b2Smrg /* Hence attempting to use add_fixit_insert_after at the end of the line
11213ad841b2Smrg should now fail. */
11223ad841b2Smrg richloc.add_fixit_insert_after ("/* inserted */");
11233ad841b2Smrg ASSERT_TRUE (richloc.seen_impossible_fixit_p ());
11243ad841b2Smrg
11253ad841b2Smrg edit_context edit;
11263ad841b2Smrg edit.add_fixits (&richloc);
11273ad841b2Smrg ASSERT_FALSE (edit.valid_p ());
11283ad841b2Smrg ASSERT_EQ (NULL, edit.get_content (filename));
11293ad841b2Smrg ASSERT_EQ (NULL, edit.generate_diff (false));
11303ad841b2Smrg }
11313ad841b2Smrg
1132cef8759bSmrg /* Test applying an "insert" fixit that adds a newline. */
1133cef8759bSmrg
1134cef8759bSmrg static void
test_applying_fixits_insert_containing_newline(const line_table_case & case_)1135cef8759bSmrg test_applying_fixits_insert_containing_newline (const line_table_case &case_)
1136cef8759bSmrg {
1137cef8759bSmrg /* Create a tempfile and write some text to it.
1138cef8759bSmrg .........................0000000001111111.
1139cef8759bSmrg .........................1234567890123456. */
1140cef8759bSmrg const char *old_content = (" case 'a':\n" /* line 1. */
1141cef8759bSmrg " x = a;\n" /* line 2. */
1142cef8759bSmrg " case 'b':\n" /* line 3. */
1143cef8759bSmrg " x = b;\n");/* line 4. */
1144cef8759bSmrg
1145cef8759bSmrg temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
1146cef8759bSmrg const char *filename = tmp.get_filename ();
1147cef8759bSmrg line_table_test ltt (case_);
1148cef8759bSmrg linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 3);
1149cef8759bSmrg
1150cef8759bSmrg /* Add a "break;" on a line by itself before line 3 i.e. before
1151cef8759bSmrg column 1 of line 3. */
1152cef8759bSmrg location_t case_start = linemap_position_for_column (line_table, 5);
1153cef8759bSmrg location_t case_finish = linemap_position_for_column (line_table, 13);
1154cef8759bSmrg location_t case_loc = make_location (case_start, case_start, case_finish);
1155cef8759bSmrg rich_location richloc (line_table, case_loc);
1156cef8759bSmrg location_t line_start = linemap_position_for_column (line_table, 1);
1157cef8759bSmrg richloc.add_fixit_insert_before (line_start, " break;\n");
1158cef8759bSmrg
1159cef8759bSmrg if (case_finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
1160cef8759bSmrg return;
1161cef8759bSmrg
1162cef8759bSmrg edit_context edit;
1163cef8759bSmrg edit.add_fixits (&richloc);
1164cef8759bSmrg auto_free <char *> new_content = edit.get_content (filename);
1165cef8759bSmrg ASSERT_STREQ ((" case 'a':\n"
1166cef8759bSmrg " x = a;\n"
1167cef8759bSmrg " break;\n"
1168cef8759bSmrg " case 'b':\n"
1169cef8759bSmrg " x = b;\n"),
1170cef8759bSmrg new_content);
1171cef8759bSmrg
1172cef8759bSmrg /* Verify diff. */
1173cef8759bSmrg auto_free <char *> diff = edit.generate_diff (false);
1174cef8759bSmrg ASSERT_STREQ (("@@ -1,4 +1,5 @@\n"
1175cef8759bSmrg " case 'a':\n"
1176cef8759bSmrg " x = a;\n"
1177cef8759bSmrg "+ break;\n"
1178cef8759bSmrg " case 'b':\n"
1179cef8759bSmrg " x = b;\n"),
1180cef8759bSmrg diff);
1181cef8759bSmrg }
1182cef8759bSmrg
11833ad841b2Smrg /* Test applying a "replace" fixit that grows the affected line. */
11843ad841b2Smrg
11853ad841b2Smrg static void
test_applying_fixits_growing_replace(const line_table_case & case_)11863ad841b2Smrg test_applying_fixits_growing_replace (const line_table_case &case_)
11873ad841b2Smrg {
11883ad841b2Smrg /* Create a tempfile and write some text to it.
11893ad841b2Smrg .........................0000000001111111.
11903ad841b2Smrg .........................1234567890123456. */
11913ad841b2Smrg const char *old_content = ("/* before */\n"
11923ad841b2Smrg "foo = bar.field;\n"
11933ad841b2Smrg "/* after */\n");
11943ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
11953ad841b2Smrg const char *filename = tmp.get_filename ();
11963ad841b2Smrg line_table_test ltt (case_);
11973ad841b2Smrg linemap_add (line_table, LC_ENTER, false, filename, 2);
11983ad841b2Smrg
11993ad841b2Smrg /* Replace "field" with "m_field". */
12003ad841b2Smrg location_t start = linemap_position_for_column (line_table, 11);
12013ad841b2Smrg location_t finish = linemap_position_for_column (line_table, 15);
12023ad841b2Smrg location_t field = make_location (start, start, finish);
12033ad841b2Smrg rich_location richloc (line_table, field);
12043ad841b2Smrg richloc.add_fixit_replace ("m_field");
12053ad841b2Smrg
12063ad841b2Smrg edit_context edit;
12073ad841b2Smrg edit.add_fixits (&richloc);
12083ad841b2Smrg auto_free <char *> new_content = edit.get_content (filename);
12093ad841b2Smrg if (finish <= LINE_MAP_MAX_LOCATION_WITH_COLS)
12103ad841b2Smrg {
12113ad841b2Smrg ASSERT_STREQ ("/* before */\n"
12123ad841b2Smrg "foo = bar.m_field;\n"
12133ad841b2Smrg "/* after */\n", new_content);
12143ad841b2Smrg
12153ad841b2Smrg /* Verify location of ";" after the change. */
12163ad841b2Smrg ASSERT_EQ (18, edit.get_effective_column (filename, 2, 16));
12173ad841b2Smrg
12183ad841b2Smrg /* Verify diff. */
12193ad841b2Smrg auto_free <char *> diff = edit.generate_diff (false);
12203ad841b2Smrg ASSERT_STREQ ("@@ -1,3 +1,3 @@\n"
12213ad841b2Smrg " /* before */\n"
12223ad841b2Smrg "-foo = bar.field;\n"
12233ad841b2Smrg "+foo = bar.m_field;\n"
12243ad841b2Smrg " /* after */\n", diff);
12253ad841b2Smrg }
12263ad841b2Smrg }
12273ad841b2Smrg
12283ad841b2Smrg /* Test applying a "replace" fixit that shrinks the affected line. */
12293ad841b2Smrg
12303ad841b2Smrg static void
test_applying_fixits_shrinking_replace(const line_table_case & case_)12313ad841b2Smrg test_applying_fixits_shrinking_replace (const line_table_case &case_)
12323ad841b2Smrg {
12333ad841b2Smrg /* Create a tempfile and write some text to it.
12343ad841b2Smrg .........................000000000111111111.
12353ad841b2Smrg .........................123456789012345678. */
12363ad841b2Smrg const char *old_content = ("/* before */\n"
12373ad841b2Smrg "foo = bar.m_field;\n"
12383ad841b2Smrg "/* after */\n");
12393ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
12403ad841b2Smrg const char *filename = tmp.get_filename ();
12413ad841b2Smrg line_table_test ltt (case_);
12423ad841b2Smrg linemap_add (line_table, LC_ENTER, false, filename, 2);
12433ad841b2Smrg
12443ad841b2Smrg /* Replace "field" with "m_field". */
12453ad841b2Smrg location_t start = linemap_position_for_column (line_table, 11);
12463ad841b2Smrg location_t finish = linemap_position_for_column (line_table, 17);
12473ad841b2Smrg location_t m_field = make_location (start, start, finish);
12483ad841b2Smrg rich_location richloc (line_table, m_field);
12493ad841b2Smrg richloc.add_fixit_replace ("field");
12503ad841b2Smrg
12513ad841b2Smrg edit_context edit;
12523ad841b2Smrg edit.add_fixits (&richloc);
12533ad841b2Smrg auto_free <char *> new_content = edit.get_content (filename);
12543ad841b2Smrg if (finish <= LINE_MAP_MAX_LOCATION_WITH_COLS)
12553ad841b2Smrg {
12563ad841b2Smrg ASSERT_STREQ ("/* before */\n"
12573ad841b2Smrg "foo = bar.field;\n"
12583ad841b2Smrg "/* after */\n", new_content);
12593ad841b2Smrg
12603ad841b2Smrg /* Verify location of ";" after the change. */
12613ad841b2Smrg ASSERT_EQ (16, edit.get_effective_column (filename, 2, 18));
12623ad841b2Smrg
12633ad841b2Smrg /* Verify diff. */
12643ad841b2Smrg auto_free <char *> diff = edit.generate_diff (false);
12653ad841b2Smrg ASSERT_STREQ ("@@ -1,3 +1,3 @@\n"
12663ad841b2Smrg " /* before */\n"
12673ad841b2Smrg "-foo = bar.m_field;\n"
12683ad841b2Smrg "+foo = bar.field;\n"
12693ad841b2Smrg " /* after */\n", diff);
12703ad841b2Smrg }
12713ad841b2Smrg }
12723ad841b2Smrg
1273cef8759bSmrg /* Replacement fix-it hint containing a newline. */
1274cef8759bSmrg
1275cef8759bSmrg static void
test_applying_fixits_replace_containing_newline(const line_table_case & case_)1276cef8759bSmrg test_applying_fixits_replace_containing_newline (const line_table_case &case_)
1277cef8759bSmrg {
1278cef8759bSmrg /* Create a tempfile and write some text to it.
1279cef8759bSmrg .........................0000000001111.
1280cef8759bSmrg .........................1234567890123. */
1281cef8759bSmrg const char *old_content = "foo = bar ();\n";
1282cef8759bSmrg
1283cef8759bSmrg temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
1284cef8759bSmrg const char *filename = tmp.get_filename ();
1285cef8759bSmrg line_table_test ltt (case_);
1286cef8759bSmrg linemap_add (line_table, LC_ENTER, false, filename, 1);
1287cef8759bSmrg
1288cef8759bSmrg /* Replace the " = " with "\n = ", as if we were reformatting an
1289cef8759bSmrg overly long line. */
1290cef8759bSmrg location_t start = linemap_position_for_column (line_table, 4);
1291cef8759bSmrg location_t finish = linemap_position_for_column (line_table, 6);
1292cef8759bSmrg location_t loc = linemap_position_for_column (line_table, 13);
1293cef8759bSmrg rich_location richloc (line_table, loc);
1294cef8759bSmrg source_range range = source_range::from_locations (start, finish);
1295cef8759bSmrg richloc.add_fixit_replace (range, "\n = ");
1296cef8759bSmrg
1297cef8759bSmrg /* Newlines are only supported within fix-it hints that
1298cef8759bSmrg are at the start of lines (for entirely new lines), hence
1299cef8759bSmrg this fix-it should not be displayed. */
1300cef8759bSmrg ASSERT_TRUE (richloc.seen_impossible_fixit_p ());
1301cef8759bSmrg
1302cef8759bSmrg if (finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
1303cef8759bSmrg return;
1304cef8759bSmrg
1305cef8759bSmrg edit_context edit;
1306cef8759bSmrg edit.add_fixits (&richloc);
1307cef8759bSmrg auto_free <char *> new_content = edit.get_content (filename);
1308cef8759bSmrg //ASSERT_STREQ ("foo\n = bar ();\n", new_content);
1309cef8759bSmrg }
1310cef8759bSmrg
13113ad841b2Smrg /* Test applying a "remove" fixit. */
13123ad841b2Smrg
13133ad841b2Smrg static void
test_applying_fixits_remove(const line_table_case & case_)13143ad841b2Smrg test_applying_fixits_remove (const line_table_case &case_)
13153ad841b2Smrg {
13163ad841b2Smrg /* Create a tempfile and write some text to it.
13173ad841b2Smrg .........................000000000111111111.
13183ad841b2Smrg .........................123456789012345678. */
13193ad841b2Smrg const char *old_content = ("/* before */\n"
13203ad841b2Smrg "foo = bar.m_field;\n"
13213ad841b2Smrg "/* after */\n");
13223ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
13233ad841b2Smrg const char *filename = tmp.get_filename ();
13243ad841b2Smrg line_table_test ltt (case_);
13253ad841b2Smrg linemap_add (line_table, LC_ENTER, false, filename, 2);
13263ad841b2Smrg
13273ad841b2Smrg /* Remove ".m_field". */
13283ad841b2Smrg location_t start = linemap_position_for_column (line_table, 10);
13293ad841b2Smrg location_t finish = linemap_position_for_column (line_table, 17);
13303ad841b2Smrg rich_location richloc (line_table, start);
13313ad841b2Smrg source_range range;
13323ad841b2Smrg range.m_start = start;
13333ad841b2Smrg range.m_finish = finish;
13343ad841b2Smrg richloc.add_fixit_remove (range);
13353ad841b2Smrg
13363ad841b2Smrg edit_context edit;
13373ad841b2Smrg edit.add_fixits (&richloc);
13383ad841b2Smrg auto_free <char *> new_content = edit.get_content (filename);
13393ad841b2Smrg if (finish <= LINE_MAP_MAX_LOCATION_WITH_COLS)
13403ad841b2Smrg {
13413ad841b2Smrg ASSERT_STREQ ("/* before */\n"
13423ad841b2Smrg "foo = bar;\n"
13433ad841b2Smrg "/* after */\n", new_content);
13443ad841b2Smrg
13453ad841b2Smrg /* Verify location of ";" after the change. */
13463ad841b2Smrg ASSERT_EQ (10, edit.get_effective_column (filename, 2, 18));
13473ad841b2Smrg
13483ad841b2Smrg /* Verify diff. */
13493ad841b2Smrg auto_free <char *> diff = edit.generate_diff (false);
13503ad841b2Smrg ASSERT_STREQ ("@@ -1,3 +1,3 @@\n"
13513ad841b2Smrg " /* before */\n"
13523ad841b2Smrg "-foo = bar.m_field;\n"
13533ad841b2Smrg "+foo = bar;\n"
13543ad841b2Smrg " /* after */\n", diff);
13553ad841b2Smrg }
13563ad841b2Smrg }
13573ad841b2Smrg
13583ad841b2Smrg /* Test applying multiple fixits to one line. */
13593ad841b2Smrg
13603ad841b2Smrg static void
test_applying_fixits_multiple(const line_table_case & case_)13613ad841b2Smrg test_applying_fixits_multiple (const line_table_case &case_)
13623ad841b2Smrg {
13633ad841b2Smrg /* Create a tempfile and write some text to it.
13643ad841b2Smrg .........................00000000011111111.
13653ad841b2Smrg .........................12345678901234567. */
13663ad841b2Smrg const char *old_content = ("/* before */\n"
13673ad841b2Smrg "foo = bar.field;\n"
13683ad841b2Smrg "/* after */\n");
13693ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
13703ad841b2Smrg const char *filename = tmp.get_filename ();
13713ad841b2Smrg line_table_test ltt (case_);
13723ad841b2Smrg linemap_add (line_table, LC_ENTER, false, filename, 2);
13733ad841b2Smrg
13743ad841b2Smrg location_t c7 = linemap_position_for_column (line_table, 7);
13753ad841b2Smrg location_t c9 = linemap_position_for_column (line_table, 9);
13763ad841b2Smrg location_t c11 = linemap_position_for_column (line_table, 11);
13773ad841b2Smrg location_t c15 = linemap_position_for_column (line_table, 15);
13783ad841b2Smrg location_t c17 = linemap_position_for_column (line_table, 17);
13793ad841b2Smrg
13803ad841b2Smrg if (c17 > LINE_MAP_MAX_LOCATION_WITH_COLS)
13813ad841b2Smrg return;
13823ad841b2Smrg
13833ad841b2Smrg /* Add a comment in front of "bar.field". */
13843ad841b2Smrg rich_location insert_a (line_table, c7);
13853ad841b2Smrg insert_a.add_fixit_insert_before (c7, "/* alpha */");
13863ad841b2Smrg
13873ad841b2Smrg /* Add a comment after "bar.field;". */
13883ad841b2Smrg rich_location insert_b (line_table, c17);
13893ad841b2Smrg insert_b.add_fixit_insert_before (c17, "/* beta */");
13903ad841b2Smrg
13913ad841b2Smrg /* Replace "bar" with "pub". */
13923ad841b2Smrg rich_location replace_a (line_table, c7);
13933ad841b2Smrg replace_a.add_fixit_replace (source_range::from_locations (c7, c9),
13943ad841b2Smrg "pub");
13953ad841b2Smrg
13963ad841b2Smrg /* Replace "field" with "meadow". */
13973ad841b2Smrg rich_location replace_b (line_table, c7);
13983ad841b2Smrg replace_b.add_fixit_replace (source_range::from_locations (c11, c15),
13993ad841b2Smrg "meadow");
14003ad841b2Smrg
14013ad841b2Smrg edit_context edit;
14023ad841b2Smrg edit.add_fixits (&insert_a);
14033ad841b2Smrg ASSERT_EQ (100, edit.get_effective_column (filename, 1, 100));
14043ad841b2Smrg ASSERT_EQ (1, edit.get_effective_column (filename, 2, 1));
14053ad841b2Smrg ASSERT_EQ (6, edit.get_effective_column (filename, 2, 6));
14063ad841b2Smrg ASSERT_EQ (18, edit.get_effective_column (filename, 2, 7));
14073ad841b2Smrg ASSERT_EQ (27, edit.get_effective_column (filename, 2, 16));
14083ad841b2Smrg ASSERT_EQ (100, edit.get_effective_column (filename, 3, 100));
14093ad841b2Smrg
14103ad841b2Smrg edit.add_fixits (&insert_b);
14113ad841b2Smrg edit.add_fixits (&replace_a);
14123ad841b2Smrg edit.add_fixits (&replace_b);
14133ad841b2Smrg
14143ad841b2Smrg if (c17 <= LINE_MAP_MAX_LOCATION_WITH_COLS)
14153ad841b2Smrg {
14163ad841b2Smrg auto_free <char *> new_content = edit.get_content (tmp.get_filename ());
14173ad841b2Smrg ASSERT_STREQ ("/* before */\n"
14183ad841b2Smrg "foo = /* alpha */pub.meadow;/* beta */\n"
14193ad841b2Smrg "/* after */\n",
14203ad841b2Smrg new_content);
14213ad841b2Smrg
14223ad841b2Smrg /* Verify diff. */
14233ad841b2Smrg auto_free <char *> diff = edit.generate_diff (false);
14243ad841b2Smrg ASSERT_STREQ ("@@ -1,3 +1,3 @@\n"
14253ad841b2Smrg " /* before */\n"
14263ad841b2Smrg "-foo = bar.field;\n"
14273ad841b2Smrg "+foo = /* alpha */pub.meadow;/* beta */\n"
14283ad841b2Smrg " /* after */\n", diff);
14293ad841b2Smrg }
14303ad841b2Smrg }
14313ad841b2Smrg
14323ad841b2Smrg /* Subroutine of test_applying_fixits_multiple_lines.
14333ad841b2Smrg Add the text "CHANGED: " to the front of the given line. */
14343ad841b2Smrg
14353ad841b2Smrg static location_t
change_line(edit_context & edit,int line_num)14363ad841b2Smrg change_line (edit_context &edit, int line_num)
14373ad841b2Smrg {
14383ad841b2Smrg const line_map_ordinary *ord_map
14393ad841b2Smrg = LINEMAPS_LAST_ORDINARY_MAP (line_table);
14403ad841b2Smrg const int column = 1;
14413ad841b2Smrg location_t loc =
14423ad841b2Smrg linemap_position_for_line_and_column (line_table, ord_map,
14433ad841b2Smrg line_num, column);
14443ad841b2Smrg
14453ad841b2Smrg expanded_location exploc = expand_location (loc);
14463ad841b2Smrg if (loc <= LINE_MAP_MAX_LOCATION_WITH_COLS)
14473ad841b2Smrg {
14483ad841b2Smrg ASSERT_EQ (line_num, exploc.line);
14493ad841b2Smrg ASSERT_EQ (column, exploc.column);
14503ad841b2Smrg }
14513ad841b2Smrg
14523ad841b2Smrg rich_location insert (line_table, loc);
14533ad841b2Smrg insert.add_fixit_insert_before ("CHANGED: ");
14543ad841b2Smrg edit.add_fixits (&insert);
14553ad841b2Smrg return loc;
14563ad841b2Smrg }
14573ad841b2Smrg
1458cef8759bSmrg /* Subroutine of test_applying_fixits_multiple_lines.
1459cef8759bSmrg Add the text "INSERTED\n" in front of the given line. */
1460cef8759bSmrg
1461cef8759bSmrg static location_t
insert_line(edit_context & edit,int line_num)1462cef8759bSmrg insert_line (edit_context &edit, int line_num)
1463cef8759bSmrg {
1464cef8759bSmrg const line_map_ordinary *ord_map
1465cef8759bSmrg = LINEMAPS_LAST_ORDINARY_MAP (line_table);
1466cef8759bSmrg const int column = 1;
1467cef8759bSmrg location_t loc =
1468cef8759bSmrg linemap_position_for_line_and_column (line_table, ord_map,
1469cef8759bSmrg line_num, column);
1470cef8759bSmrg
1471cef8759bSmrg expanded_location exploc = expand_location (loc);
1472cef8759bSmrg if (loc <= LINE_MAP_MAX_LOCATION_WITH_COLS)
1473cef8759bSmrg {
1474cef8759bSmrg ASSERT_EQ (line_num, exploc.line);
1475cef8759bSmrg ASSERT_EQ (column, exploc.column);
1476cef8759bSmrg }
1477cef8759bSmrg
1478cef8759bSmrg rich_location insert (line_table, loc);
1479cef8759bSmrg insert.add_fixit_insert_before ("INSERTED\n");
1480cef8759bSmrg edit.add_fixits (&insert);
1481cef8759bSmrg return loc;
1482cef8759bSmrg }
1483cef8759bSmrg
14843ad841b2Smrg /* Test of editing multiple lines within a long file,
14853ad841b2Smrg to ensure that diffs are generated as expected. */
14863ad841b2Smrg
14873ad841b2Smrg static void
test_applying_fixits_multiple_lines(const line_table_case & case_)14883ad841b2Smrg test_applying_fixits_multiple_lines (const line_table_case &case_)
14893ad841b2Smrg {
14903ad841b2Smrg /* Create a tempfile and write many lines of text to it. */
14913ad841b2Smrg named_temp_file tmp (".txt");
14923ad841b2Smrg const char *filename = tmp.get_filename ();
14933ad841b2Smrg FILE *f = fopen (filename, "w");
14943ad841b2Smrg ASSERT_NE (f, NULL);
14953ad841b2Smrg for (int i = 1; i <= 1000; i++)
14963ad841b2Smrg fprintf (f, "line %i\n", i);
14973ad841b2Smrg fclose (f);
14983ad841b2Smrg
14993ad841b2Smrg line_table_test ltt (case_);
15003ad841b2Smrg linemap_add (line_table, LC_ENTER, false, filename, 1);
15013ad841b2Smrg linemap_position_for_column (line_table, 127);
15023ad841b2Smrg
15033ad841b2Smrg edit_context edit;
15043ad841b2Smrg
15053ad841b2Smrg /* A run of consecutive lines. */
15063ad841b2Smrg change_line (edit, 2);
15073ad841b2Smrg change_line (edit, 3);
15083ad841b2Smrg change_line (edit, 4);
1509cef8759bSmrg insert_line (edit, 5);
15103ad841b2Smrg
15113ad841b2Smrg /* A run of nearby lines, within the contextual limit. */
15123ad841b2Smrg change_line (edit, 150);
15133ad841b2Smrg change_line (edit, 151);
15143ad841b2Smrg location_t last_loc = change_line (edit, 153);
15153ad841b2Smrg
15163ad841b2Smrg if (last_loc > LINE_MAP_MAX_LOCATION_WITH_COLS)
15173ad841b2Smrg return;
15183ad841b2Smrg
15193ad841b2Smrg /* Verify diff. */
15203ad841b2Smrg auto_free <char *> diff = edit.generate_diff (false);
1521cef8759bSmrg ASSERT_STREQ ("@@ -1,7 +1,8 @@\n"
15223ad841b2Smrg " line 1\n"
15233ad841b2Smrg "-line 2\n"
15243ad841b2Smrg "-line 3\n"
15253ad841b2Smrg "-line 4\n"
15263ad841b2Smrg "+CHANGED: line 2\n"
15273ad841b2Smrg "+CHANGED: line 3\n"
15283ad841b2Smrg "+CHANGED: line 4\n"
1529cef8759bSmrg "+INSERTED\n"
15303ad841b2Smrg " line 5\n"
15313ad841b2Smrg " line 6\n"
15323ad841b2Smrg " line 7\n"
1533cef8759bSmrg "@@ -147,10 +148,10 @@\n"
15343ad841b2Smrg " line 147\n"
15353ad841b2Smrg " line 148\n"
15363ad841b2Smrg " line 149\n"
15373ad841b2Smrg "-line 150\n"
15383ad841b2Smrg "-line 151\n"
15393ad841b2Smrg "+CHANGED: line 150\n"
15403ad841b2Smrg "+CHANGED: line 151\n"
15413ad841b2Smrg " line 152\n"
15423ad841b2Smrg "-line 153\n"
15433ad841b2Smrg "+CHANGED: line 153\n"
15443ad841b2Smrg " line 154\n"
15453ad841b2Smrg " line 155\n"
15463ad841b2Smrg " line 156\n", diff);
15473ad841b2Smrg
15483ad841b2Smrg /* Ensure tmp stays alive until this point, so that the tempfile
15493ad841b2Smrg persists until after the generate_diff call. */
15503ad841b2Smrg tmp.get_filename ();
15513ad841b2Smrg }
15523ad841b2Smrg
15533ad841b2Smrg /* Test of converting an initializer for a named field from
15543ad841b2Smrg the old GCC extension to C99 syntax.
15553ad841b2Smrg Exercises a shrinking replacement followed by a growing
15563ad841b2Smrg replacement on the same line. */
15573ad841b2Smrg
15583ad841b2Smrg static void
test_applying_fixits_modernize_named_init(const line_table_case & case_)15593ad841b2Smrg test_applying_fixits_modernize_named_init (const line_table_case &case_)
15603ad841b2Smrg {
15613ad841b2Smrg /* Create a tempfile and write some text to it.
15623ad841b2Smrg .........................00000000011111111.
15633ad841b2Smrg .........................12345678901234567. */
15643ad841b2Smrg const char *old_content = ("/* before */\n"
15653ad841b2Smrg "bar : 1,\n"
15663ad841b2Smrg "/* after */\n");
15673ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
15683ad841b2Smrg const char *filename = tmp.get_filename ();
15693ad841b2Smrg line_table_test ltt (case_);
15703ad841b2Smrg linemap_add (line_table, LC_ENTER, false, filename, 2);
15713ad841b2Smrg
15723ad841b2Smrg location_t c1 = linemap_position_for_column (line_table, 1);
15733ad841b2Smrg location_t c3 = linemap_position_for_column (line_table, 3);
15743ad841b2Smrg location_t c8 = linemap_position_for_column (line_table, 8);
15753ad841b2Smrg
15763ad841b2Smrg if (c8 > LINE_MAP_MAX_LOCATION_WITH_COLS)
15773ad841b2Smrg return;
15783ad841b2Smrg
15793ad841b2Smrg /* Replace "bar" with ".". */
15803ad841b2Smrg rich_location r1 (line_table, c8);
15813ad841b2Smrg r1.add_fixit_replace (source_range::from_locations (c1, c3),
15823ad841b2Smrg ".");
15833ad841b2Smrg
15843ad841b2Smrg /* Replace ":" with "bar =". */
15853ad841b2Smrg rich_location r2 (line_table, c8);
15863ad841b2Smrg r2.add_fixit_replace (source_range::from_locations (c8, c8),
15873ad841b2Smrg "bar =");
15883ad841b2Smrg
15893ad841b2Smrg /* The order should not matter. Do r1 then r2. */
15903ad841b2Smrg {
15913ad841b2Smrg edit_context edit;
15923ad841b2Smrg edit.add_fixits (&r1);
15933ad841b2Smrg
15943ad841b2Smrg /* Verify state after first replacement. */
15953ad841b2Smrg {
15963ad841b2Smrg auto_free <char *> new_content = edit.get_content (tmp.get_filename ());
15973ad841b2Smrg /* We should now have:
15983ad841b2Smrg ............00000000011.
15993ad841b2Smrg ............12345678901. */
16003ad841b2Smrg ASSERT_STREQ ("/* before */\n"
16013ad841b2Smrg ". : 1,\n"
16023ad841b2Smrg "/* after */\n",
16033ad841b2Smrg new_content);
16043ad841b2Smrg /* Location of the "1". */
16053ad841b2Smrg ASSERT_EQ (6, edit.get_effective_column (filename, 2, 8));
16063ad841b2Smrg /* Location of the ",". */
16073ad841b2Smrg ASSERT_EQ (9, edit.get_effective_column (filename, 2, 11));
16083ad841b2Smrg }
16093ad841b2Smrg
16103ad841b2Smrg edit.add_fixits (&r2);
16113ad841b2Smrg
16123ad841b2Smrg auto_free <char *> new_content = edit.get_content (tmp.get_filename ());
16133ad841b2Smrg /* Verify state after second replacement.
16143ad841b2Smrg ............00000000011111111.
16153ad841b2Smrg ............12345678901234567. */
16163ad841b2Smrg ASSERT_STREQ ("/* before */\n"
16173ad841b2Smrg ". bar = 1,\n"
16183ad841b2Smrg "/* after */\n",
16193ad841b2Smrg new_content);
16203ad841b2Smrg }
16213ad841b2Smrg
16223ad841b2Smrg /* Try again, doing r2 then r1; the new_content should be the same. */
16233ad841b2Smrg {
16243ad841b2Smrg edit_context edit;
16253ad841b2Smrg edit.add_fixits (&r2);
16263ad841b2Smrg edit.add_fixits (&r1);
16273ad841b2Smrg auto_free <char *> new_content = edit.get_content (tmp.get_filename ());
16283ad841b2Smrg /*.............00000000011111111.
16293ad841b2Smrg .............12345678901234567. */
16303ad841b2Smrg ASSERT_STREQ ("/* before */\n"
16313ad841b2Smrg ". bar = 1,\n"
16323ad841b2Smrg "/* after */\n",
16333ad841b2Smrg new_content);
16343ad841b2Smrg }
16353ad841b2Smrg }
16363ad841b2Smrg
16373ad841b2Smrg /* Test of a fixit affecting a file that can't be read. */
16383ad841b2Smrg
16393ad841b2Smrg static void
test_applying_fixits_unreadable_file()16403ad841b2Smrg test_applying_fixits_unreadable_file ()
16413ad841b2Smrg {
16423ad841b2Smrg const char *filename = "this-does-not-exist.txt";
1643*4c3eb207Smrg line_table_test ltt;
16443ad841b2Smrg linemap_add (line_table, LC_ENTER, false, filename, 1);
16453ad841b2Smrg
16463ad841b2Smrg location_t loc = linemap_position_for_column (line_table, 1);
16473ad841b2Smrg
16483ad841b2Smrg rich_location insert (line_table, loc);
16493ad841b2Smrg insert.add_fixit_insert_before ("change 1");
16503ad841b2Smrg insert.add_fixit_insert_before ("change 2");
16513ad841b2Smrg
16523ad841b2Smrg edit_context edit;
16533ad841b2Smrg /* Attempting to add the fixits affecting the unreadable file
16543ad841b2Smrg should transition the edit from valid to invalid. */
16553ad841b2Smrg ASSERT_TRUE (edit.valid_p ());
16563ad841b2Smrg edit.add_fixits (&insert);
16573ad841b2Smrg ASSERT_FALSE (edit.valid_p ());
16583ad841b2Smrg ASSERT_EQ (NULL, edit.get_content (filename));
16593ad841b2Smrg ASSERT_EQ (NULL, edit.generate_diff (false));
16603ad841b2Smrg }
16613ad841b2Smrg
16623ad841b2Smrg /* Verify that we gracefully handle an attempt to edit a line
16633ad841b2Smrg that's beyond the end of the file. */
16643ad841b2Smrg
16653ad841b2Smrg static void
test_applying_fixits_line_out_of_range()16663ad841b2Smrg test_applying_fixits_line_out_of_range ()
16673ad841b2Smrg {
16683ad841b2Smrg /* Create a tempfile and write some text to it.
16693ad841b2Smrg ........................00000000011111111.
16703ad841b2Smrg ........................12345678901234567. */
16713ad841b2Smrg const char *old_content = "One-liner file\n";
16723ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".txt", old_content);
16733ad841b2Smrg const char *filename = tmp.get_filename ();
1674*4c3eb207Smrg line_table_test ltt;
16753ad841b2Smrg linemap_add (line_table, LC_ENTER, false, filename, 2);
16763ad841b2Smrg
16773ad841b2Smrg /* Try to insert a string in line 2. */
16783ad841b2Smrg location_t loc = linemap_position_for_column (line_table, 1);
16793ad841b2Smrg
16803ad841b2Smrg rich_location insert (line_table, loc);
16813ad841b2Smrg insert.add_fixit_insert_before ("change");
16823ad841b2Smrg
16833ad841b2Smrg /* Verify that attempting the insertion puts an edit_context
16843ad841b2Smrg into an invalid state. */
16853ad841b2Smrg edit_context edit;
16863ad841b2Smrg ASSERT_TRUE (edit.valid_p ());
16873ad841b2Smrg edit.add_fixits (&insert);
16883ad841b2Smrg ASSERT_FALSE (edit.valid_p ());
16893ad841b2Smrg ASSERT_EQ (NULL, edit.get_content (filename));
16903ad841b2Smrg ASSERT_EQ (NULL, edit.generate_diff (false));
16913ad841b2Smrg }
16923ad841b2Smrg
16933ad841b2Smrg /* Verify the boundary conditions of column values in fix-it
16943ad841b2Smrg hints applied to edit_context instances. */
16953ad841b2Smrg
16963ad841b2Smrg static void
test_applying_fixits_column_validation(const line_table_case & case_)16973ad841b2Smrg test_applying_fixits_column_validation (const line_table_case &case_)
16983ad841b2Smrg {
16993ad841b2Smrg /* Create a tempfile and write some text to it.
17003ad841b2Smrg ........................00000000011111111.
17013ad841b2Smrg ........................12345678901234567. */
17023ad841b2Smrg const char *old_content = "One-liner file\n";
17033ad841b2Smrg temp_source_file tmp (SELFTEST_LOCATION, ".txt", old_content);
17043ad841b2Smrg const char *filename = tmp.get_filename ();
17053ad841b2Smrg line_table_test ltt (case_);
17063ad841b2Smrg linemap_add (line_table, LC_ENTER, false, filename, 1);
17073ad841b2Smrg
17083ad841b2Smrg location_t c11 = linemap_position_for_column (line_table, 11);
17093ad841b2Smrg location_t c14 = linemap_position_for_column (line_table, 14);
17103ad841b2Smrg location_t c15 = linemap_position_for_column (line_table, 15);
17113ad841b2Smrg location_t c16 = linemap_position_for_column (line_table, 16);
17123ad841b2Smrg
17133ad841b2Smrg /* Verify limits of valid columns in insertion fixits. */
17143ad841b2Smrg
17153ad841b2Smrg /* Verify inserting at the end of the line. */
17163ad841b2Smrg {
17173ad841b2Smrg rich_location richloc (line_table, c11);
17183ad841b2Smrg richloc.add_fixit_insert_before (c15, " change");
17193ad841b2Smrg
17203ad841b2Smrg /* Col 15 is at the end of the line, so the insertion
17213ad841b2Smrg should succeed. */
17223ad841b2Smrg edit_context edit;
17233ad841b2Smrg edit.add_fixits (&richloc);
17243ad841b2Smrg auto_free <char *> new_content = edit.get_content (tmp.get_filename ());
17253ad841b2Smrg if (c15 <= LINE_MAP_MAX_LOCATION_WITH_COLS)
17263ad841b2Smrg ASSERT_STREQ ("One-liner file change\n", new_content);
17273ad841b2Smrg else
17283ad841b2Smrg ASSERT_EQ (NULL, new_content);
17293ad841b2Smrg }
17303ad841b2Smrg
17313ad841b2Smrg /* Verify inserting beyond the end of the line. */
17323ad841b2Smrg {
17333ad841b2Smrg rich_location richloc (line_table, c11);
17343ad841b2Smrg richloc.add_fixit_insert_before (c16, " change");
17353ad841b2Smrg
17363ad841b2Smrg /* Col 16 is beyond the end of the line, so the insertion
17373ad841b2Smrg should fail gracefully. */
17383ad841b2Smrg edit_context edit;
17393ad841b2Smrg ASSERT_TRUE (edit.valid_p ());
17403ad841b2Smrg edit.add_fixits (&richloc);
17413ad841b2Smrg ASSERT_FALSE (edit.valid_p ());
17423ad841b2Smrg ASSERT_EQ (NULL, edit.get_content (filename));
17433ad841b2Smrg ASSERT_EQ (NULL, edit.generate_diff (false));
17443ad841b2Smrg }
17453ad841b2Smrg
17463ad841b2Smrg /* Verify limits of valid columns in replacement fixits. */
17473ad841b2Smrg
17483ad841b2Smrg /* Verify replacing the end of the line. */
17493ad841b2Smrg {
17503ad841b2Smrg rich_location richloc (line_table, c11);
17513ad841b2Smrg source_range range = source_range::from_locations (c11, c14);
17523ad841b2Smrg richloc.add_fixit_replace (range, "change");
17533ad841b2Smrg
17543ad841b2Smrg /* Col 14 is at the end of the line, so the replacement
17553ad841b2Smrg should succeed. */
17563ad841b2Smrg edit_context edit;
17573ad841b2Smrg edit.add_fixits (&richloc);
17583ad841b2Smrg auto_free <char *> new_content = edit.get_content (tmp.get_filename ());
17593ad841b2Smrg if (c14 <= LINE_MAP_MAX_LOCATION_WITH_COLS)
17603ad841b2Smrg ASSERT_STREQ ("One-liner change\n", new_content);
17613ad841b2Smrg else
17623ad841b2Smrg ASSERT_EQ (NULL, new_content);
17633ad841b2Smrg }
17643ad841b2Smrg
17653ad841b2Smrg /* Verify going beyond the end of the line. */
17663ad841b2Smrg {
17673ad841b2Smrg rich_location richloc (line_table, c11);
17683ad841b2Smrg source_range range = source_range::from_locations (c11, c15);
17693ad841b2Smrg richloc.add_fixit_replace (range, "change");
17703ad841b2Smrg
17713ad841b2Smrg /* Col 15 is after the end of the line, so the replacement
17723ad841b2Smrg should fail; verify that the attempt fails gracefully. */
17733ad841b2Smrg edit_context edit;
17743ad841b2Smrg ASSERT_TRUE (edit.valid_p ());
17753ad841b2Smrg edit.add_fixits (&richloc);
17763ad841b2Smrg ASSERT_FALSE (edit.valid_p ());
17773ad841b2Smrg ASSERT_EQ (NULL, edit.get_content (filename));
17783ad841b2Smrg ASSERT_EQ (NULL, edit.generate_diff (false));
17793ad841b2Smrg }
17803ad841b2Smrg }
17813ad841b2Smrg
17823ad841b2Smrg /* Run all of the selftests within this file. */
17833ad841b2Smrg
17843ad841b2Smrg void
edit_context_c_tests()17853ad841b2Smrg edit_context_c_tests ()
17863ad841b2Smrg {
17873ad841b2Smrg test_get_content ();
17883ad841b2Smrg for_each_line_table_case (test_applying_fixits_insert_before);
17893ad841b2Smrg for_each_line_table_case (test_applying_fixits_insert_after);
17903ad841b2Smrg for_each_line_table_case (test_applying_fixits_insert_after_at_line_end);
17913ad841b2Smrg for_each_line_table_case (test_applying_fixits_insert_after_failure);
1792cef8759bSmrg for_each_line_table_case (test_applying_fixits_insert_containing_newline);
17933ad841b2Smrg for_each_line_table_case (test_applying_fixits_growing_replace);
17943ad841b2Smrg for_each_line_table_case (test_applying_fixits_shrinking_replace);
1795cef8759bSmrg for_each_line_table_case (test_applying_fixits_replace_containing_newline);
17963ad841b2Smrg for_each_line_table_case (test_applying_fixits_remove);
17973ad841b2Smrg for_each_line_table_case (test_applying_fixits_multiple);
17983ad841b2Smrg for_each_line_table_case (test_applying_fixits_multiple_lines);
17993ad841b2Smrg for_each_line_table_case (test_applying_fixits_modernize_named_init);
18003ad841b2Smrg test_applying_fixits_unreadable_file ();
18013ad841b2Smrg test_applying_fixits_line_out_of_range ();
18023ad841b2Smrg for_each_line_table_case (test_applying_fixits_column_validation);
18033ad841b2Smrg }
18043ad841b2Smrg
18053ad841b2Smrg } // namespace selftest
18063ad841b2Smrg
18073ad841b2Smrg #endif /* CHECKING_P */
1808