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