Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | |
| 3 | """Script to sort the top-most block of #include lines. |
| 4 | |
| 5 | Assumes the LLVM coding conventions. |
| 6 | |
| 7 | Currently, this script only bothers sorting the llvm/... headers. Patches |
| 8 | welcome for more functionality, and sorting other header groups. |
| 9 | """ |
| 10 | |
| 11 | import argparse |
| 12 | import os |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 13 | |
| 14 | def sort_includes(f): |
Chandler Carruth | 43342d5 | 2012-12-04 07:04:58 +0000 | [diff] [blame] | 15 | """Sort the #include lines of a specific file.""" |
Chandler Carruth | 2aa2a9b | 2012-12-04 09:59:54 +0000 | [diff] [blame^] | 16 | |
| 17 | # Skip files which are under INPUTS trees or test trees. |
| 18 | if 'INPUTS/' in f.name or 'test/' in f.name: |
| 19 | return |
| 20 | |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 21 | lines = f.readlines() |
Chandler Carruth | 43342d5 | 2012-12-04 07:04:58 +0000 | [diff] [blame] | 22 | look_for_api_header = os.path.splitext(f.name)[1] == '.cpp' |
| 23 | found_headers = False |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 24 | headers_begin = 0 |
| 25 | headers_end = 0 |
| 26 | api_headers = [] |
| 27 | local_headers = [] |
| 28 | project_headers = [] |
| 29 | system_headers = [] |
| 30 | for (i, l) in enumerate(lines): |
| 31 | if l.strip() == '': |
| 32 | continue |
| 33 | if l.startswith('#include'): |
Chandler Carruth | 43342d5 | 2012-12-04 07:04:58 +0000 | [diff] [blame] | 34 | if not found_headers: |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 35 | headers_begin = i |
Chandler Carruth | 43342d5 | 2012-12-04 07:04:58 +0000 | [diff] [blame] | 36 | found_headers = True |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 37 | headers_end = i |
| 38 | header = l[len('#include'):].lstrip() |
| 39 | if look_for_api_header and header.startswith('"'): |
| 40 | api_headers.append(header) |
| 41 | look_for_api_header = False |
| 42 | continue |
Chandler Carruth | ed09f45 | 2012-12-04 09:44:38 +0000 | [diff] [blame] | 43 | if header.startswith('<') or header.startswith('"gtest/'): |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 44 | system_headers.append(header) |
| 45 | continue |
Chandler Carruth | 43342d5 | 2012-12-04 07:04:58 +0000 | [diff] [blame] | 46 | if (header.startswith('"llvm/') or header.startswith('"llvm-c/') or |
| 47 | header.startswith('"clang/') or header.startswith('"clang-c/')): |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 48 | project_headers.append(header) |
| 49 | continue |
| 50 | local_headers.append(header) |
| 51 | continue |
| 52 | |
| 53 | # Only allow comments and #defines prior to any includes. If either are |
| 54 | # mixed with includes, the order might be sensitive. |
Chandler Carruth | 43342d5 | 2012-12-04 07:04:58 +0000 | [diff] [blame] | 55 | if found_headers: |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 56 | break |
Chandler Carruth | 6a451d0 | 2012-12-03 17:01:46 +0000 | [diff] [blame] | 57 | if l.startswith('//') or l.startswith('#define') or l.startswith('#ifndef'): |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 58 | continue |
| 59 | break |
Chandler Carruth | 43342d5 | 2012-12-04 07:04:58 +0000 | [diff] [blame] | 60 | if not found_headers: |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 61 | return |
| 62 | |
| 63 | local_headers.sort() |
| 64 | project_headers.sort() |
| 65 | system_headers.sort() |
| 66 | headers = api_headers + local_headers + project_headers + system_headers |
| 67 | header_lines = ['#include ' + h for h in headers] |
| 68 | lines = lines[:headers_begin] + header_lines + lines[headers_end + 1:] |
| 69 | |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 70 | f.seek(0) |
| 71 | f.truncate() |
| 72 | f.writelines(lines) |
| 73 | |
| 74 | def main(): |
| 75 | parser = argparse.ArgumentParser(description=__doc__) |
| 76 | parser.add_argument('files', nargs='+', type=argparse.FileType('r+'), |
| 77 | help='the source files to sort includes within') |
| 78 | args = parser.parse_args() |
| 79 | for f in args.files: |
| 80 | sort_includes(f) |
| 81 | |
| 82 | if __name__ == '__main__': |
| 83 | main() |