1  /* Run expensive selftests.  */
       2  /* { dg-options "-O" } */
       3  
       4  #include "gcc-plugin.h"
       5  #include "config.h"
       6  #include "system.h"
       7  #include "coretypes.h"
       8  #include "diagnostic.h"
       9  #include "edit-context.h"
      10  #include "selftest.h"
      11  #include "selftest-diagnostic.h"
      12  
      13  int plugin_is_GPL_compatible;
      14  
      15  #if CHECKING_P
      16  
      17  namespace selftest {
      18  
      19  /* Subroutine of test_fixit_on_very_long_line.
      20     Verify that LOC has the EXPECTED_COLUMN, apart from the various
      21     cases where it can't.  */
      22  
      23  static void
      24  verify_column (location_t loc,
      25  	       const line_map_ordinary *ord_map,
      26  	       int line_width,
      27  	       int expected_column)
      28  {
      29    ASSERT_TRUE (/* Normal case.  */
      30  	       LOCATION_COLUMN (loc) == expected_column
      31  	       /* ord_map can't store columns e.g. due to
      32  		  max_column_hint being too high.  */
      33  	       || ord_map->m_column_and_range_bits == 0
      34  	       /* Running out of location_t values.  */
      35  	       || loc > LINE_MAP_MAX_LOCATION_WITH_COLS
      36  	       /* column exceeds LINE_MAP_MAX_COLUMN_NUMBER.  */
      37  	       || expected_column > (int)LINE_MAP_MAX_COLUMN_NUMBER
      38  	       /* column exceeds max_column_hint for ord_map.  */
      39  	       || expected_column > line_width);
      40  }
      41  
      42  /* Subroutine of test_fixit_on_very_long_line.
      43     Run various things for RICHLOC, but don't check; we just want them
      44     to survive.  */
      45  
      46  static void
      47  test_richloc (rich_location *richloc)
      48  {
      49    /* Run the diagnostic and fix-it printing code.  */
      50    test_diagnostic_context dc;
      51    diagnostic_show_locus (&dc, richloc, DK_ERROR);
      52  
      53    /* Generate a diff.  */
      54    edit_context ec;
      55    ec.add_fixits (richloc);
      56    char *diff = ec.generate_diff (true);
      57    free (diff);
      58  }
      59  
      60  /* Verify that the fix-it-printing code can cope with very long lines
      61     (PR c/82050).  */
      62  
      63  static void
      64  test_fixit_on_very_long_line (const line_table_case &case_)
      65  {
      66    /* Various interesting column/line-width values, to try to tickle
      67       out bugs.  */
      68    const int VERY_LONG_LINE = 8192;
      69    const int columns[] = {0,
      70  			 1,
      71  			 80,
      72  			 LINE_MAP_MAX_COLUMN_NUMBER - 2,
      73  			 LINE_MAP_MAX_COLUMN_NUMBER - 1,
      74  			 LINE_MAP_MAX_COLUMN_NUMBER,
      75  			 LINE_MAP_MAX_COLUMN_NUMBER + 1,
      76  			 LINE_MAP_MAX_COLUMN_NUMBER + 2,
      77  			 VERY_LONG_LINE,
      78  			 VERY_LONG_LINE + 5};
      79    for (unsigned int width_idx = 0; width_idx < ARRAY_SIZE (columns);
      80         width_idx++)
      81      {
      82        int line_width = columns[width_idx];
      83  
      84        /* Create a source file with a very long line.  */
      85        named_temp_file tmp (".c");
      86        FILE *f = fopen (tmp.get_filename (), "w");
      87        for (int i = 0; i < line_width; i++)
      88  	fputc (' ', f);
      89        fputc ('\n', f);
      90        fclose (f);
      91  
      92        line_table_test ltt (case_);
      93        const line_map_ordinary *ord_map = linemap_check_ordinary
      94  	(linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
      95        linemap_line_start (line_table, 1, line_width);
      96  
      97        for (unsigned int start_idx = 0; start_idx < ARRAY_SIZE (columns);
      98  	   start_idx++)
      99  	{
     100  	  int start_col = columns[start_idx];
     101  	  location_t start_loc
     102  	    = linemap_position_for_line_and_column (line_table, ord_map, 1,
     103  						    start_col);
     104  	  verify_column (start_loc, ord_map, line_width, start_col);
     105  	  for (unsigned int finish_idx = 0; finish_idx < ARRAY_SIZE (columns);
     106  	       finish_idx++)
     107  	    {
     108  	      int finish_col = columns[finish_idx];
     109  	      location_t finish_loc
     110  		= linemap_position_for_line_and_column (line_table, ord_map, 1,
     111  							finish_col);
     112  	      verify_column (finish_loc, ord_map, line_width, finish_col);
     113  
     114  	      /* Now use start-finish to exercise the fix-it code.
     115  		 In each case, run the printing code, but don't check;
     116  		 we just want it to survive.  */
     117  
     118  	      /* Insertion.  */
     119  	      {
     120  		rich_location richloc (line_table, start_loc);
     121  		richloc.add_fixit_insert_after (start_loc, "insertion");
     122  		test_richloc (&richloc);
     123  	      }
     124  
     125  	      /* Replacement.  */
     126  	      {
     127  		rich_location richloc (line_table, start_loc);
     128  		source_range range
     129  		  = source_range::from_locations (start_loc, finish_loc);
     130  		richloc.add_fixit_replace (range, "replacement");
     131  		test_richloc (&richloc);
     132  	      }
     133  
     134  	      /* Deletion.  */
     135  	      {
     136  		rich_location richloc (line_table, start_loc);
     137  		source_range range
     138  		  = source_range::from_locations (start_loc, finish_loc);
     139  		richloc.add_fixit_remove (range);
     140  		test_richloc (&richloc);
     141  	      }
     142  	    }
     143  	}
     144      }
     145  }
     146  
     147  /* Callback handler for the PLUGIN_FINISH event.
     148     At this point, all GCC subsystems should be initialized and
     149     "warmed up"; this is where we run our unit tests.  */
     150  
     151  static void
     152  expensive_tests (void */*gcc_data*/, void */*user_data*/)
     153  {
     154    test_runner r ("expensive_selftests_plugin");
     155  
     156    for_each_line_table_case (test_fixit_on_very_long_line);
     157  }
     158  
     159  } // namespace selftest
     160  
     161  #endif /* #if CHECKING_P */
     162  
     163  int
     164  plugin_init (struct plugin_name_args *plugin_info,
     165  	     struct plugin_gcc_version *version)
     166  {
     167  #if CHECKING_P
     168    const char *plugin_name = plugin_info->base_name;
     169    register_callback (plugin_info->base_name,
     170  		     PLUGIN_FINISH,
     171  		     selftest::expensive_tests,
     172  		     NULL); /* void *user_data */
     173  #else
     174    inform (UNKNOWN_LOCATION, "self-tests are not enabled in this build");
     175  #endif /* #if CHECKING_P */
     176    return 0;
     177  }