Add a concept of 'barrier' #includes that we will not sort
around. This concept is intended for fragile #includes that require something else to be #included before them or they don't run properly. By setting them as a barrier include, we guarantee no include will be reordered from before it to after it. For now, the only barrier #includes are <linux/foo>. Sometimes you need to #include linux includes in a particular order for things to compile; we don't want fix_includes to mess with that. Note that each barrier include is treated separately -- if we see two <linux/foo> #includes next to each other, we will leave them each alone, we won't treat them as a group and consider sorting them. R=dsturtevant DELTA=83 (74 added, 0 deleted, 9 changed) Revision created by MOE tool push_codebase. MOE_MIGRATION=1346
This commit is contained in:
parent
3183022744
commit
7d2240f212
|
@ -126,6 +126,13 @@ _LINE_TYPES = [_COMMENT_LINE_RE, _BLANK_LINE_RE,
|
|||
_INCLUDE_RE, _FORWARD_DECLARE_RE,
|
||||
]
|
||||
|
||||
# A regexp matching #include lines that should not be sorted -- that
|
||||
# is, we should never reorganize the code so an #include that used to
|
||||
# come before this line now comes after, or vice versa. This can be
|
||||
# used for 'fragile' #includes that require other #includes to happen
|
||||
# before them to function properly.
|
||||
_NOSORT_INCLUDES = re.compile(r'^\s*#\s*include\s+(<linux/)')
|
||||
|
||||
|
||||
class FixIncludesError(Exception):
|
||||
pass
|
||||
|
@ -661,6 +668,15 @@ def _CalculateMoveSpans(file_lines, forward_declare_spans):
|
|||
file_lines[i].move_span = (span_begin, span_end)
|
||||
|
||||
|
||||
def _IsNosortInclude(file_lines, line_range):
|
||||
"""Returns true iff some line in [line_range[0], line_range[1]) is _NOSORT."""
|
||||
for line_number in apply(xrange, line_range):
|
||||
if (not file_lines[line_number].deleted and
|
||||
_NOSORT_INCLUDES.search(file_lines[line_number].line)):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _LinesAreAllBlank(file_lines, start_line, end_line):
|
||||
"""Returns true iff all lines in [start_line, end_line) are blank/deleted."""
|
||||
for line_number in xrange(start_line, end_line):
|
||||
|
@ -682,10 +698,17 @@ def _CalculateReorderSpans(file_lines):
|
|||
and namespaces freely inside a reorder span.
|
||||
|
||||
Calculating reorder_span is easy: they're just the union of
|
||||
continguous move-spans (with perhaps blank lines and comments
|
||||
contiguous move-spans (with perhaps blank lines and comments
|
||||
thrown in), because move-spans share the 'no actual code'
|
||||
requirement.
|
||||
|
||||
There's one exception: if any move-span matches the _NOSORT_INCLUDES
|
||||
regexp, it means that we should consider that move-span to be a
|
||||
'barrier': nothing should get reordered from one side of that
|
||||
move-span to the other. (This is used for #includes that depend on
|
||||
other #includes being before them to function properly.) We do that
|
||||
by putting them into their own reorder span.
|
||||
|
||||
For lines of type _INCLUDE_RE or _FORWARD_DECLARE_RE, the reorder
|
||||
span is set to the tuple [start_of_span, end_of_span). All other
|
||||
lines have an arbitrary value for the reorder span.
|
||||
|
@ -701,14 +724,19 @@ def _CalculateReorderSpans(file_lines):
|
|||
i = 0
|
||||
while i < len(sorted_move_spans):
|
||||
reorder_span_start = sorted_move_spans[i][0]
|
||||
# Add in the next move span if we're connected to it only by blank lines.
|
||||
while i < len(sorted_move_spans) - 1:
|
||||
move_span_end = sorted_move_spans[i][1]
|
||||
next_move_span_start = sorted_move_spans[i+1][0]
|
||||
if _LinesAreAllBlank(file_lines, move_span_end, next_move_span_start):
|
||||
i += 1
|
||||
else:
|
||||
break
|
||||
|
||||
# If we're a 'nosort' include, we're always in a reorder span of
|
||||
# our own. Otherwise, add in the next move span if we're
|
||||
# connected to it only by blank lines.
|
||||
if not _IsNosortInclude(file_lines, sorted_move_spans[i]):
|
||||
while i < len(sorted_move_spans) - 1:
|
||||
move_span_end = sorted_move_spans[i][1]
|
||||
next_move_span_start = sorted_move_spans[i+1][0]
|
||||
if (_LinesAreAllBlank(file_lines, move_span_end, next_move_span_start)
|
||||
and not _IsNosortInclude(file_lines, sorted_move_spans[i+1])):
|
||||
i += 1
|
||||
else:
|
||||
break
|
||||
reorder_span_end = sorted_move_spans[i][1]
|
||||
# We'll map every line in the span to the span-extent.
|
||||
for line_number in xrange(reorder_span_start, reorder_span_end):
|
||||
|
|
|
@ -2204,6 +2204,52 @@ int main() { return 0; }
|
|||
self.assertListEqual([], self.actual_after_contents)
|
||||
self.assertEqual(0, num_files_modified)
|
||||
|
||||
def testNosortIncludes(self):
|
||||
"""Tests that we correctly sort 'around' _NOSORT_INCLUDES."""
|
||||
infile = """\
|
||||
// Copyright 2010
|
||||
|
||||
#include <linux/a_stay_top.h>
|
||||
#include <stdlib.h> ///-
|
||||
#include <linux/can_sort_around_this_deleted_include> ///-
|
||||
#include <stdio.h>
|
||||
///+#include <stdlib.h>
|
||||
#include "user/include.h"
|
||||
///+#include "user/new_include.h"
|
||||
#include <linux/c_stay_second.h>
|
||||
#include <linux/b_stay_third.h>
|
||||
#include <ctype.h>
|
||||
#include <cpp_include>
|
||||
///+#include <new_cpp_include>
|
||||
#include <linux/d_stay_fourth.h>
|
||||
|
||||
int main() { return 0; }
|
||||
"""
|
||||
iwyu_output = """\
|
||||
nosort_includes.h should add these lines:
|
||||
#include "user/new_include.h"
|
||||
#include <new_cpp_include>
|
||||
|
||||
nosort_includes.h should remove these lines:
|
||||
- #include <linux/can_sort_around_this_deleted_include> // lines 5-5
|
||||
|
||||
The full include-list for nosort_includes.h:
|
||||
#include "user/include.h"
|
||||
#include "user/new_include.h"
|
||||
#include <cpp_include>
|
||||
#include <ctype.h>
|
||||
#include <linux/a_stay_top.h>
|
||||
#include <linux/b_stay_third.h>
|
||||
#include <linux/c_stay_second.h>
|
||||
#include <linux/d_stay_fourth.h>
|
||||
#include <new_cpp_include>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
---
|
||||
"""
|
||||
self.RegisterFileContents({'nosort_includes.h': infile})
|
||||
self.ProcessAndTest(iwyu_output)
|
||||
|
||||
def testSortingProjectIncludesAuto(self):
|
||||
"""Check that project includes can be sorted separately."""
|
||||
infile = """\
|
||||
|
|
Loading…
Reference in New Issue