comparison gcc/c-family/c-indentation.c @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
comparison
equal deleted inserted replaced
111:04ced10e8804 131:84e7813d76e9
1 /* Implementation of -Wmisleading-indentation 1 /* Implementation of -Wmisleading-indentation
2 Copyright (C) 2015-2017 Free Software Foundation, Inc. 2 Copyright (C) 2015-2018 Free Software Foundation, Inc.
3 3
4 This file is part of GCC. 4 This file is part of GCC.
5 5
6 GCC is free software; you can redistribute it and/or modify it under 6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free 7 the terms of the GNU General Public License as published by the Free
21 #include "system.h" 21 #include "system.h"
22 #include "coretypes.h" 22 #include "coretypes.h"
23 #include "tm.h" 23 #include "tm.h"
24 #include "c-common.h" 24 #include "c-common.h"
25 #include "c-indentation.h" 25 #include "c-indentation.h"
26 #include "selftest.h"
26 27
27 extern cpp_options *cpp_opts; 28 extern cpp_options *cpp_opts;
28 29
29 /* Round up VIS_COLUMN to nearest tab stop. */ 30 /* Round up VIS_COLUMN to nearest tab stop. */
30 31
31 static unsigned int 32 static unsigned int
32 next_tab_stop (unsigned int vis_column) 33 next_tab_stop (unsigned int vis_column, unsigned int tab_width)
33 { 34 {
34 const unsigned int tab_width = cpp_opts->tabstop;
35 vis_column = ((vis_column + tab_width) / tab_width) * tab_width; 35 vis_column = ((vis_column + tab_width) / tab_width) * tab_width;
36 return vis_column; 36 return vis_column;
37 } 37 }
38 38
39 /* Convert libcpp's notion of a column (a 1-based char count) to 39 /* Convert libcpp's notion of a column (a 1-based char count) to
41 relevant line. 41 relevant line.
42 42
43 Returns true if a conversion was possible, writing the result to OUT, 43 Returns true if a conversion was possible, writing the result to OUT,
44 otherwise returns false. If FIRST_NWS is not NULL, then write to it 44 otherwise returns false. If FIRST_NWS is not NULL, then write to it
45 the visual column corresponding to the first non-whitespace character 45 the visual column corresponding to the first non-whitespace character
46 on the line. */ 46 on the line (up to or before EXPLOC). */
47 47
48 static bool 48 static bool
49 get_visual_column (expanded_location exploc, location_t loc, 49 get_visual_column (expanded_location exploc, location_t loc,
50 unsigned int *out, 50 unsigned int *out,
51 unsigned int *first_nws) 51 unsigned int *first_nws,
52 unsigned int tab_width)
52 { 53 {
53 /* PR c++/68819: if the column number is zero, we presumably 54 /* PR c++/68819: if the column number is zero, we presumably
54 had a location_t > LINE_MAP_MAX_LOCATION_WITH_COLS, and so 55 had a location_t > LINE_MAP_MAX_LOCATION_WITH_COLS, and so
55 we have no column information. 56 we have no column information.
56 Act as if no conversion was possible, triggering the 57 Act as if no conversion was possible, triggering the
68 " the size of the code/headers"); 69 " the size of the code/headers");
69 } 70 }
70 return false; 71 return false;
71 } 72 }
72 73
73 int line_len; 74 char_span line = location_get_source_line (exploc.file, exploc.line);
74 const char *line = location_get_source_line (exploc.file, exploc.line,
75 &line_len);
76 if (!line) 75 if (!line)
76 return false;
77 if ((size_t)exploc.column > line.length ())
77 return false; 78 return false;
78 unsigned int vis_column = 0; 79 unsigned int vis_column = 0;
79 for (int i = 1; i < exploc.column; i++) 80 for (int i = 1; i < exploc.column; i++)
80 { 81 {
81 unsigned char ch = line[i - 1]; 82 unsigned char ch = line[i - 1];
85 *first_nws = vis_column; 86 *first_nws = vis_column;
86 first_nws = NULL; 87 first_nws = NULL;
87 } 88 }
88 89
89 if (ch == '\t') 90 if (ch == '\t')
90 vis_column = next_tab_stop (vis_column); 91 vis_column = next_tab_stop (vis_column, tab_width);
91 else 92 else
92 vis_column++; 93 vis_column++;
93 } 94 }
94 95
95 if (first_nws != NULL) 96 if (first_nws != NULL)
106 *FIRST_NWS. 107 *FIRST_NWS.
107 Otherwise, return false, leaving *FIRST_NWS untouched. */ 108 Otherwise, return false, leaving *FIRST_NWS untouched. */
108 109
109 static bool 110 static bool
110 get_first_nws_vis_column (const char *file, int line_num, 111 get_first_nws_vis_column (const char *file, int line_num,
111 unsigned int *first_nws) 112 unsigned int *first_nws,
113 unsigned int tab_width)
112 { 114 {
113 gcc_assert (first_nws); 115 gcc_assert (first_nws);
114 116
115 int line_len; 117 char_span line = location_get_source_line (file, line_num);
116 const char *line = location_get_source_line (file, line_num, &line_len);
117 if (!line) 118 if (!line)
118 return false; 119 return false;
119 unsigned int vis_column = 0; 120 unsigned int vis_column = 0;
120 for (int i = 1; i < line_len; i++) 121 for (size_t i = 1; i < line.length (); i++)
121 { 122 {
122 unsigned char ch = line[i - 1]; 123 unsigned char ch = line[i - 1];
123 124
124 if (!ISSPACE (ch)) 125 if (!ISSPACE (ch))
125 { 126 {
126 *first_nws = vis_column; 127 *first_nws = vis_column;
127 return true; 128 return true;
128 } 129 }
129 130
130 if (ch == '\t') 131 if (ch == '\t')
131 vis_column = next_tab_stop (vis_column); 132 vis_column = next_tab_stop (vis_column, tab_width);
132 else 133 else
133 vis_column++; 134 vis_column++;
134 } 135 }
135 136
136 /* No non-whitespace characters found. */ 137 /* No non-whitespace characters found. */
179 180
180 static bool 181 static bool
181 detect_intervening_unindent (const char *file, 182 detect_intervening_unindent (const char *file,
182 int body_line, 183 int body_line,
183 int next_stmt_line, 184 int next_stmt_line,
184 unsigned int vis_column) 185 unsigned int vis_column,
186 unsigned int tab_width)
185 { 187 {
186 gcc_assert (file); 188 gcc_assert (file);
187 gcc_assert (next_stmt_line > body_line); 189 gcc_assert (next_stmt_line > body_line);
188 190
189 for (int line = body_line + 1; line < next_stmt_line; line++) 191 for (int line = body_line + 1; line < next_stmt_line; line++)
190 { 192 {
191 unsigned int line_vis_column; 193 unsigned int line_vis_column;
192 if (get_first_nws_vis_column (file, line, &line_vis_column)) 194 if (get_first_nws_vis_column (file, line, &line_vis_column, tab_width))
193 if (line_vis_column < vis_column) 195 if (line_vis_column < vis_column)
194 return true; 196 return true;
195 } 197 }
196 198
197 /* Not found. */ 199 /* Not found. */
289 return false; 291 return false;
290 292
291 expanded_location body_exploc = expand_location (body_loc); 293 expanded_location body_exploc = expand_location (body_loc);
292 expanded_location next_stmt_exploc = expand_location (next_stmt_loc); 294 expanded_location next_stmt_exploc = expand_location (next_stmt_loc);
293 expanded_location guard_exploc = expand_location (guard_loc); 295 expanded_location guard_exploc = expand_location (guard_loc);
296
297 const unsigned int tab_width = cpp_opts->tabstop;
294 298
295 /* They must be in the same file. */ 299 /* They must be in the same file. */
296 if (next_stmt_exploc.file != body_exploc.file) 300 if (next_stmt_exploc.file != body_exploc.file)
297 return false; 301 return false;
298 302
335 gcc_assert (guard_exploc.line == next_stmt_exploc.line); 339 gcc_assert (guard_exploc.line == next_stmt_exploc.line);
336 unsigned int guard_vis_column; 340 unsigned int guard_vis_column;
337 unsigned int guard_line_first_nws; 341 unsigned int guard_line_first_nws;
338 if (!get_visual_column (guard_exploc, guard_loc, 342 if (!get_visual_column (guard_exploc, guard_loc,
339 &guard_vis_column, 343 &guard_vis_column,
340 &guard_line_first_nws)) 344 &guard_line_first_nws, tab_width))
341 return false; 345 return false;
342 /* Heuristic: only warn if the guard is the first thing 346 /* Heuristic: only warn if the guard is the first thing
343 on its line. */ 347 on its line. */
344 if (guard_vis_column == guard_line_first_nws) 348 if (guard_vis_column == guard_line_first_nws)
345 return true; 349 return true;
395 the case for input files containing #line directives, and these 399 the case for input files containing #line directives, and these
396 are often for autogenerated sources (e.g. from .md files), where 400 are often for autogenerated sources (e.g. from .md files), where
397 it's not clear that it's meaningful to look at indentation. */ 401 it's not clear that it's meaningful to look at indentation. */
398 if (!get_visual_column (next_stmt_exploc, next_stmt_loc, 402 if (!get_visual_column (next_stmt_exploc, next_stmt_loc,
399 &next_stmt_vis_column, 403 &next_stmt_vis_column,
400 &next_stmt_line_first_nws)) 404 &next_stmt_line_first_nws, tab_width))
401 return false; 405 return false;
402 if (!get_visual_column (body_exploc, body_loc, 406 if (!get_visual_column (body_exploc, body_loc,
403 &body_vis_column, 407 &body_vis_column,
404 &body_line_first_nws)) 408 &body_line_first_nws, tab_width))
405 return false; 409 return false;
406 if (!get_visual_column (guard_exploc, guard_loc, 410 if (!get_visual_column (guard_exploc, guard_loc,
407 &guard_vis_column, 411 &guard_vis_column,
408 &guard_line_first_nws)) 412 &guard_line_first_nws, tab_width))
409 return false; 413 return false;
410 414
411 /* If the line where the next stmt starts has non-whitespace 415 /* If the line where the next stmt starts has non-whitespace
412 on it before the stmt, then don't warn: 416 on it before the stmt, then don't warn:
413 #define emit 417 #define emit
487 491
488 /* Don't warn if there is an unindent between the two statements. */ 492 /* Don't warn if there is an unindent between the two statements. */
489 int vis_column = MIN (next_stmt_vis_column, body_vis_column); 493 int vis_column = MIN (next_stmt_vis_column, body_vis_column);
490 if (detect_intervening_unindent (body_exploc.file, body_exploc.line, 494 if (detect_intervening_unindent (body_exploc.file, body_exploc.line,
491 next_stmt_exploc.line, 495 next_stmt_exploc.line,
492 vis_column)) 496 vis_column, tab_width))
493 return false; 497 return false;
494 498
495 /* Otherwise, they are visually aligned: issue a warning. */ 499 /* Otherwise, they are visually aligned: issue a warning. */
496 return true; 500 return true;
497 } 501 }
603 607
604 if (should_warn_for_misleading_indentation (guard_tinfo, 608 if (should_warn_for_misleading_indentation (guard_tinfo,
605 body_tinfo, 609 body_tinfo,
606 next_tinfo)) 610 next_tinfo))
607 { 611 {
612 auto_diagnostic_group d;
608 if (warning_at (guard_tinfo.location, OPT_Wmisleading_indentation, 613 if (warning_at (guard_tinfo.location, OPT_Wmisleading_indentation,
609 "this %qs clause does not guard...", 614 "this %qs clause does not guard...",
610 guard_tinfo_to_string (guard_tinfo.keyword))) 615 guard_tinfo_to_string (guard_tinfo.keyword)))
611 inform (next_tinfo.location, 616 inform (next_tinfo.location,
612 "...this statement, but the latter is misleadingly indented" 617 "...this statement, but the latter is misleadingly indented"
613 " as if it were guarded by the %qs", 618 " as if it were guarded by the %qs",
614 guard_tinfo_to_string (guard_tinfo.keyword)); 619 guard_tinfo_to_string (guard_tinfo.keyword));
615 } 620 }
616 } 621 }
622
623 #if CHECKING_P
624
625 namespace selftest {
626
627 /* Verify that next_tab_stop works as expected. */
628
629 static void
630 test_next_tab_stop ()
631 {
632 const unsigned int tab_width = 8;
633
634 ASSERT_EQ (next_tab_stop (0, tab_width), 8);
635 ASSERT_EQ (next_tab_stop (1, tab_width), 8);
636 ASSERT_EQ (next_tab_stop (7, tab_width), 8);
637
638 ASSERT_EQ (next_tab_stop (8, tab_width), 16);
639 ASSERT_EQ (next_tab_stop (9, tab_width), 16);
640 ASSERT_EQ (next_tab_stop (15, tab_width), 16);
641
642 ASSERT_EQ (next_tab_stop (16, tab_width), 24);
643 ASSERT_EQ (next_tab_stop (17, tab_width), 24);
644 ASSERT_EQ (next_tab_stop (23, tab_width), 24);
645 }
646
647 /* Verify that the given call to get_visual_column succeeds, with
648 the given results. */
649
650 static void
651 assert_get_visual_column_succeeds (const location &loc,
652 const char *file, int line, int column,
653 const unsigned int tab_width,
654 unsigned int expected_visual_column,
655 unsigned int expected_first_nws)
656 {
657 expanded_location exploc;
658 exploc.file = file;
659 exploc.line = line;
660 exploc.column = column;
661 exploc.data = NULL;
662 exploc.sysp = false;
663 unsigned int actual_visual_column;
664 unsigned int actual_first_nws;
665 bool result = get_visual_column (exploc, UNKNOWN_LOCATION,
666 &actual_visual_column,
667 &actual_first_nws, tab_width);
668 ASSERT_TRUE_AT (loc, result);
669 ASSERT_EQ_AT (loc, actual_visual_column, expected_visual_column);
670 ASSERT_EQ_AT (loc, actual_first_nws, expected_first_nws);
671 }
672
673 /* Verify that the given call to get_visual_column succeeds, with
674 the given results. */
675
676 #define ASSERT_GET_VISUAL_COLUMN_SUCCEEDS(FILENAME, LINE, COLUMN, \
677 TAB_WIDTH, \
678 EXPECTED_VISUAL_COLUMN, \
679 EXPECTED_FIRST_NWS) \
680 SELFTEST_BEGIN_STMT \
681 assert_get_visual_column_succeeds (SELFTEST_LOCATION, \
682 FILENAME, LINE, COLUMN, \
683 TAB_WIDTH, \
684 EXPECTED_VISUAL_COLUMN, \
685 EXPECTED_FIRST_NWS); \
686 SELFTEST_END_STMT
687
688 /* Verify that the given call to get_visual_column fails gracefully. */
689
690 static void
691 assert_get_visual_column_fails (const location &loc,
692 const char *file, int line, int column,
693 const unsigned int tab_width)
694 {
695 expanded_location exploc;
696 exploc.file = file;
697 exploc.line = line;
698 exploc.column = column;
699 exploc.data = NULL;
700 exploc.sysp = false;
701 unsigned int actual_visual_column;
702 unsigned int actual_first_nws;
703 bool result = get_visual_column (exploc, UNKNOWN_LOCATION,
704 &actual_visual_column,
705 &actual_first_nws, tab_width);
706 ASSERT_FALSE_AT (loc, result);
707 }
708
709 /* Verify that the given call to get_visual_column fails gracefully. */
710
711 #define ASSERT_GET_VISUAL_COLUMN_FAILS(FILENAME, LINE, COLUMN, \
712 TAB_WIDTH) \
713 SELFTEST_BEGIN_STMT \
714 assert_get_visual_column_fails (SELFTEST_LOCATION, \
715 FILENAME, LINE, COLUMN, \
716 TAB_WIDTH); \
717 SELFTEST_END_STMT
718
719 /* Verify that get_visual_column works as expected. */
720
721 static void
722 test_get_visual_column ()
723 {
724 /* Create a tempfile with a mixture of tabs and spaces.
725
726 Both lines have either a space or a tab, then " line N",
727 for 8 characters in total.
728
729 1-based "columns" (w.r.t. to line 1):
730 .....................0000000001111.
731 .....................1234567890123. */
732 const char *content = (" line 1\n"
733 "\t line 2\n");
734 line_table_test ltt;
735 temp_source_file tmp (SELFTEST_LOCATION, ".txt", content);
736
737 const unsigned int tab_width = 8;
738 const char *file = tmp.get_filename ();
739
740 /* Line 1 (space-based indentation). */
741 {
742 const int line = 1;
743 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 1, tab_width, 0, 0);
744 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 2, tab_width, 1, 1);
745 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 3, tab_width, 2, 2);
746 /* first_nws should have stopped increasing. */
747 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 4, tab_width, 3, 2);
748 /* Verify the end-of-line boundary. */
749 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 8, tab_width, 7, 2);
750 ASSERT_GET_VISUAL_COLUMN_FAILS (file, line, 9, tab_width);
751 }
752
753 /* Line 2 (tab-based indentation). */
754 {
755 const int line = 2;
756 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 1, tab_width, 0, 0);
757 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 2, tab_width, 8, 8);
758 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 3, tab_width, 9, 9);
759 /* first_nws should have stopped increasing. */
760 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 4, tab_width, 10, 9);
761 /* Verify the end-of-line boundary. */
762 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 8, tab_width, 14, 9);
763 ASSERT_GET_VISUAL_COLUMN_FAILS (file, line, 9, tab_width);
764 }
765 }
766
767 /* Run all of the selftests within this file. */
768
769 void
770 c_indentation_c_tests ()
771 {
772 test_next_tab_stop ();
773 test_get_visual_column ();
774 }
775
776 } // namespace selftest
777
778 #endif /* CHECKING_P */