1#!/usr/bin/python2.7 2# This Source Code Form is subject to the terms of the Mozilla Public 3# License, v. 2.0. If a copy of the MPL was not distributed with this 4# file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 6import os 7import re 8import sys 9import glob 10import shutil 11import errno 12 13import ThirdPartyPaths 14 15def copy_dir_contents(src, dest): 16 for f in glob.glob("%s/*" % src): 17 try: 18 destname = "%s/%s" % (dest, os.path.basename(f)) 19 if os.path.isdir(f): 20 shutil.copytree(f, destname) 21 else: 22 shutil.copy2(f, destname) 23 except OSError as e: 24 if e.errno == errno.ENOTDIR: 25 shutil.copy2(f, destname) 26 elif e.errno == errno.EEXIST: 27 if os.path.isdir(f): 28 copy_dir_contents(f, destname) 29 else: 30 os.remove(destname) 31 shutil.copy2(f, destname) 32 else: 33 raise Exception('Directory not copied. Error: %s' % e) 34 35def write_cmake(module_path): 36 names = map(lambda f: ' ' + os.path.basename(f), 37 glob.glob("%s/*.cpp" % module_path)) 38 with open(os.path.join(module_path, 'CMakeLists.txt'), 'wb') as f: 39 f.write("""set(LLVM_LINK_COMPONENTS support) 40 41add_definitions( -DCLANG_TIDY ) 42add_definitions( -DHAVE_NEW_ASTMATCHER_NAMES ) 43 44add_clang_library(clangTidyMozillaModule 45 ThirdPartyPaths.cpp 46%(names)s 47 48 LINK_LIBS 49 clangAST 50 clangASTMatchers 51 clangBasic 52 clangLex 53 clangTidy 54 clangTidyReadabilityModule 55 clangTidyUtils 56 )""" % {'names': "\n".join(names)}) 57 58def add_item_to_cmake_section(cmake_path, section, library): 59 with open(cmake_path, 'r') as f: 60 lines = f.readlines() 61 f.close() 62 63 libs = [] 64 seen_target_libs = False 65 for line in lines: 66 if line.find(section) > -1: 67 seen_target_libs = True 68 elif seen_target_libs: 69 if line.find(')') > -1: 70 break 71 else: 72 libs.append(line.strip()) 73 libs.append(library) 74 libs = sorted(libs, key = lambda s: s.lower()) 75 76 with open(cmake_path, 'wb') as f: 77 seen_target_libs = False 78 for line in lines: 79 if line.find(section) > -1: 80 seen_target_libs = True 81 f.write(line) 82 f.writelines(map(lambda p: ' ' + p + '\n', libs)) 83 continue 84 elif seen_target_libs: 85 if line.find(')') > -1: 86 seen_target_libs = False 87 else: 88 continue 89 f.write(line) 90 91 f.close() 92 93 94def write_third_party_paths(mozilla_path, module_path): 95 tpp_txt = os.path.join(mozilla_path, '../../tools/rewriting/ThirdPartyPaths.txt') 96 with open(os.path.join(module_path, 'ThirdPartyPaths.cpp'), 'w') as f: 97 ThirdPartyPaths.generate(f, tpp_txt) 98 99 100def do_import(mozilla_path, clang_tidy_path): 101 module = 'mozilla' 102 module_path = os.path.join(clang_tidy_path, module) 103 if not os.path.isdir(module_path): 104 os.mkdir(module_path) 105 106 copy_dir_contents(mozilla_path, module_path) 107 write_third_party_paths(mozilla_path, module_path) 108 write_cmake(module_path) 109 add_item_to_cmake_section(os.path.join(module_path, '..', 'plugin', 110 'CMakeLists.txt'), 111 'LINK_LIBS', 'clangTidyMozillaModule') 112 add_item_to_cmake_section(os.path.join(module_path, '..', 'tool', 113 'CMakeLists.txt'), 114 'target_link_libraries', 'clangTidyMozillaModule') 115 with open(os.path.join(module_path, '..', 'CMakeLists.txt'), 'a') as f: 116 f.write('add_subdirectory(%s)\n' % module) 117 with open(os.path.join(module_path, '..', 'tool', 'ClangTidyMain.cpp'), 'a') as f: 118 f.write(''' 119// This anchor is used to force the linker to link the MozillaModule. 120extern volatile int MozillaModuleAnchorSource; 121static int LLVM_ATTRIBUTE_UNUSED MozillaModuleAnchorDestination = 122 MozillaModuleAnchorSource; 123''') 124 125def main(): 126 if len(sys.argv) != 3: 127 print """\ 128Usage: import_mozilla_checks.py <mozilla-clang-plugin-path> <clang-tidy-path> 129Imports the Mozilla static analysis checks into a clang-tidy source tree. 130""" 131 132 return 133 134 mozilla_path = sys.argv[1] 135 if not os.path.isdir(mozilla_path): 136 print "Invalid path to mozilla clang plugin" 137 138 clang_tidy_path = sys.argv[2] 139 if not os.path.isdir(mozilla_path): 140 print "Invalid path to clang-tidy source directory" 141 142 do_import(mozilla_path, clang_tidy_path) 143 144 145if __name__ == '__main__': 146 main() 147