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 |
| 13 | import re |
| 14 | import sys |
| 15 | import tempfile |
| 16 | |
| 17 | def sort_includes(f): |
| 18 | lines = f.readlines() |
| 19 | look_for_api_header = f.name[-4:] == '.cpp' |
| 20 | headers_begin = 0 |
| 21 | headers_end = 0 |
| 22 | api_headers = [] |
| 23 | local_headers = [] |
| 24 | project_headers = [] |
| 25 | system_headers = [] |
| 26 | for (i, l) in enumerate(lines): |
| 27 | if l.strip() == '': |
| 28 | continue |
| 29 | if l.startswith('#include'): |
| 30 | if headers_begin == 0: |
| 31 | headers_begin = i |
| 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 |
| 38 | if header.startswith('<'): |
| 39 | system_headers.append(header) |
| 40 | continue |
| 41 | if header.startswith('"llvm/') or header.startswith('"clang/'): |
| 42 | project_headers.append(header) |
| 43 | continue |
| 44 | local_headers.append(header) |
| 45 | continue |
| 46 | |
| 47 | # Only allow comments and #defines prior to any includes. If either are |
| 48 | # mixed with includes, the order might be sensitive. |
| 49 | if headers_begin != 0: |
| 50 | break |
| 51 | if l.startswith('//') or l.startswith('#define'): |
| 52 | continue |
| 53 | break |
| 54 | if headers_begin == 0: |
| 55 | return |
| 56 | |
| 57 | local_headers.sort() |
| 58 | project_headers.sort() |
| 59 | system_headers.sort() |
| 60 | headers = api_headers + local_headers + project_headers + system_headers |
| 61 | header_lines = ['#include ' + h for h in headers] |
| 62 | lines = lines[:headers_begin] + header_lines + lines[headers_end + 1:] |
| 63 | |
| 64 | #for l in lines[headers_begin:headers_end]: |
| 65 | # print l.rstrip() |
| 66 | f.seek(0) |
| 67 | f.truncate() |
| 68 | f.writelines(lines) |
| 69 | |
| 70 | def main(): |
| 71 | parser = argparse.ArgumentParser(description=__doc__) |
| 72 | parser.add_argument('files', nargs='+', type=argparse.FileType('r+'), |
| 73 | help='the source files to sort includes within') |
| 74 | args = parser.parse_args() |
| 75 | for f in args.files: |
| 76 | sort_includes(f) |
| 77 | |
| 78 | if __name__ == '__main__': |
| 79 | main() |