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 | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 16 | lines = f.readlines() |
Chandler Carruth | 43342d5 | 2012-12-04 07:04:58 +0000 | [diff] [blame] | 17 | look_for_api_header = os.path.splitext(f.name)[1] == '.cpp' |
| 18 | found_headers = False |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 19 | headers_begin = 0 |
| 20 | headers_end = 0 |
| 21 | api_headers = [] |
| 22 | local_headers = [] |
| 23 | project_headers = [] |
| 24 | system_headers = [] |
| 25 | for (i, l) in enumerate(lines): |
| 26 | if l.strip() == '': |
| 27 | continue |
| 28 | if l.startswith('#include'): |
Chandler Carruth | 43342d5 | 2012-12-04 07:04:58 +0000 | [diff] [blame] | 29 | if not found_headers: |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 30 | headers_begin = i |
Chandler Carruth | 43342d5 | 2012-12-04 07:04:58 +0000 | [diff] [blame] | 31 | found_headers = True |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 32 | headers_end = i |
| 33 | header = l[len('#include'):].lstrip() |
| 34 | if look_for_api_header and header.startswith('"'): |
| 35 | api_headers.append(header) |
| 36 | look_for_api_header = False |
| 37 | continue |
Chandler Carruth | ed09f45 | 2012-12-04 09:44:38 +0000 | [diff] [blame] | 38 | if header.startswith('<') or header.startswith('"gtest/'): |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 39 | system_headers.append(header) |
| 40 | continue |
Chandler Carruth | 43342d5 | 2012-12-04 07:04:58 +0000 | [diff] [blame] | 41 | if (header.startswith('"llvm/') or header.startswith('"llvm-c/') or |
| 42 | header.startswith('"clang/') or header.startswith('"clang-c/')): |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 43 | project_headers.append(header) |
| 44 | continue |
| 45 | local_headers.append(header) |
| 46 | continue |
| 47 | |
| 48 | # Only allow comments and #defines prior to any includes. If either are |
| 49 | # mixed with includes, the order might be sensitive. |
Chandler Carruth | 43342d5 | 2012-12-04 07:04:58 +0000 | [diff] [blame] | 50 | if found_headers: |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 51 | break |
Chandler Carruth | 6a451d0 | 2012-12-03 17:01:46 +0000 | [diff] [blame] | 52 | if l.startswith('//') or l.startswith('#define') or l.startswith('#ifndef'): |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 53 | continue |
| 54 | break |
Chandler Carruth | 43342d5 | 2012-12-04 07:04:58 +0000 | [diff] [blame] | 55 | if not found_headers: |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 56 | return |
| 57 | |
| 58 | local_headers.sort() |
| 59 | project_headers.sort() |
| 60 | system_headers.sort() |
| 61 | headers = api_headers + local_headers + project_headers + system_headers |
| 62 | header_lines = ['#include ' + h for h in headers] |
| 63 | lines = lines[:headers_begin] + header_lines + lines[headers_end + 1:] |
| 64 | |
Chandler Carruth | cba0f3d | 2012-12-03 14:23:44 +0000 | [diff] [blame] | 65 | f.seek(0) |
| 66 | f.truncate() |
| 67 | f.writelines(lines) |
| 68 | |
| 69 | def main(): |
| 70 | parser = argparse.ArgumentParser(description=__doc__) |
| 71 | parser.add_argument('files', nargs='+', type=argparse.FileType('r+'), |
| 72 | help='the source files to sort includes within') |
| 73 | args = parser.parse_args() |
| 74 | for f in args.files: |
| 75 | sort_includes(f) |
| 76 | |
| 77 | if __name__ == '__main__': |
| 78 | main() |