10cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth#!/usr/bin/env python 20cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth 30cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth"""Script to sort the top-most block of #include lines. 40cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth 50cd94c71db19c0a53d1d97f353116e271884a336Chandler CarruthAssumes the LLVM coding conventions. 60cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth 70cd94c71db19c0a53d1d97f353116e271884a336Chandler CarruthCurrently, this script only bothers sorting the llvm/... headers. Patches 80cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruthwelcome for more functionality, and sorting other header groups. 90cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth""" 100cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth 110cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruthimport argparse 120cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruthimport os 130cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth 140cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruthdef sort_includes(f): 156cb571968901701212570cbb2ab34cf4af6ba51eChandler Carruth """Sort the #include lines of a specific file.""" 16fd025797ea5197b838f87ce57f2df5bccf27ad20Chandler Carruth 17fd025797ea5197b838f87ce57f2df5bccf27ad20Chandler Carruth # Skip files which are under INPUTS trees or test trees. 18fd025797ea5197b838f87ce57f2df5bccf27ad20Chandler Carruth if 'INPUTS/' in f.name or 'test/' in f.name: 19fd025797ea5197b838f87ce57f2df5bccf27ad20Chandler Carruth return 20fd025797ea5197b838f87ce57f2df5bccf27ad20Chandler Carruth 2196ad0e8b1635eb923ef5e9c79fef8b902960dfbbChandler Carruth ext = os.path.splitext(f.name)[1] 2296ad0e8b1635eb923ef5e9c79fef8b902960dfbbChandler Carruth if ext not in ['.cpp', '.c', '.h', '.inc', '.def']: 2396ad0e8b1635eb923ef5e9c79fef8b902960dfbbChandler Carruth return 2496ad0e8b1635eb923ef5e9c79fef8b902960dfbbChandler Carruth 250cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth lines = f.readlines() 2696ad0e8b1635eb923ef5e9c79fef8b902960dfbbChandler Carruth look_for_api_header = ext in ['.cpp', '.c'] 276cb571968901701212570cbb2ab34cf4af6ba51eChandler Carruth found_headers = False 280cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth headers_begin = 0 290cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth headers_end = 0 300cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth api_headers = [] 310cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth local_headers = [] 320cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth project_headers = [] 330cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth system_headers = [] 340cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth for (i, l) in enumerate(lines): 350cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth if l.strip() == '': 360cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth continue 370cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth if l.startswith('#include'): 386cb571968901701212570cbb2ab34cf4af6ba51eChandler Carruth if not found_headers: 390cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth headers_begin = i 406cb571968901701212570cbb2ab34cf4af6ba51eChandler Carruth found_headers = True 410cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth headers_end = i 420cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth header = l[len('#include'):].lstrip() 430cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth if look_for_api_header and header.startswith('"'): 440cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth api_headers.append(header) 450cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth look_for_api_header = False 460cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth continue 471ff3d66222634fabad236423e454c0b9bd631084Chandler Carruth if header.startswith('<') or header.startswith('"gtest/'): 480cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth system_headers.append(header) 490cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth continue 506cb571968901701212570cbb2ab34cf4af6ba51eChandler Carruth if (header.startswith('"llvm/') or header.startswith('"llvm-c/') or 516cb571968901701212570cbb2ab34cf4af6ba51eChandler Carruth header.startswith('"clang/') or header.startswith('"clang-c/')): 520cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth project_headers.append(header) 530cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth continue 540cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth local_headers.append(header) 550cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth continue 560cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth 570cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth # Only allow comments and #defines prior to any includes. If either are 580cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth # mixed with includes, the order might be sensitive. 596cb571968901701212570cbb2ab34cf4af6ba51eChandler Carruth if found_headers: 600cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth break 61998aae738d2a014cb46d6e29a585fd781f95b677Chandler Carruth if l.startswith('//') or l.startswith('#define') or l.startswith('#ifndef'): 620cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth continue 630cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth break 646cb571968901701212570cbb2ab34cf4af6ba51eChandler Carruth if not found_headers: 650cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth return 660cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth 67c851438e3f2c587c5b8fb7ec4bf179798532b9f3Benjamin Kramer local_headers = sorted(set(local_headers)) 68c851438e3f2c587c5b8fb7ec4bf179798532b9f3Benjamin Kramer project_headers = sorted(set(project_headers)) 69c851438e3f2c587c5b8fb7ec4bf179798532b9f3Benjamin Kramer system_headers = sorted(set(system_headers)) 700cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth headers = api_headers + local_headers + project_headers + system_headers 710cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth header_lines = ['#include ' + h for h in headers] 720cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth lines = lines[:headers_begin] + header_lines + lines[headers_end + 1:] 730cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth 740cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth f.seek(0) 750cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth f.truncate() 760cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth f.writelines(lines) 770cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth 780cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruthdef main(): 790cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth parser = argparse.ArgumentParser(description=__doc__) 800cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth parser.add_argument('files', nargs='+', type=argparse.FileType('r+'), 810cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth help='the source files to sort includes within') 820cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth args = parser.parse_args() 830cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth for f in args.files: 840cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth sort_includes(f) 850cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth 860cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruthif __name__ == '__main__': 870cd94c71db19c0a53d1d97f353116e271884a336Chandler Carruth main() 88