Mercurial > hg > CbC > CbC_gcc
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 */ |