xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/edit-context.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
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