1#!/usr/bin/python3 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 sys 8import glob 9import shutil 10import errno 11 12import ThirdPartyPaths 13import ThreadAllows 14 15 16def copy_dir_contents(src, dest): 17 for f in glob.glob("%s/*" % src): 18 try: 19 destname = "%s/%s" % (dest, os.path.basename(f)) 20 if os.path.isdir(f): 21 shutil.copytree(f, destname) 22 else: 23 shutil.copy2(f, destname) 24 except OSError as e: 25 if e.errno == errno.ENOTDIR: 26 shutil.copy2(f, destname) 27 elif e.errno == errno.EEXIST: 28 if os.path.isdir(f): 29 copy_dir_contents(f, destname) 30 else: 31 os.remove(destname) 32 shutil.copy2(f, destname) 33 else: 34 raise Exception('Directory not copied. Error: %s' % e) 35 36 37def write_cmake(module_path, import_alpha): 38 names = [' ' + os.path.basename(f) for f in glob.glob("%s/*.cpp" % module_path)] 39 names += [' ' + os.path.basename(f) for f in glob.glob("%s/external/*.cpp" % module_path)] 40 if import_alpha: 41 alpha_names = [' ' + os.path.join("alpha", os.path.basename(f)) 42 for f in glob.glob("%s/alpha/*.cpp" % module_path)] 43 names += alpha_names 44 with open(os.path.join(module_path, 'CMakeLists.txt'), 'w') as f: 45 f.write("""set(LLVM_LINK_COMPONENTS support) 46 47add_definitions( -DCLANG_TIDY ) 48 49add_clang_library(clangTidyMozillaModule 50 ThirdPartyPaths.cpp 51%(names)s 52 53 LINK_LIBS 54 clangAST 55 clangASTMatchers 56 clangBasic 57 clangLex 58 clangTidy 59 clangTidyReadabilityModule 60 clangTidyUtils 61 clangTidyMPIModule 62 )""" % {'names': "\n".join(names)}) 63 64 65def add_moz_module(cmake_path): 66 with open(cmake_path, 'r') as f: 67 lines = f.readlines() 68 f.close() 69 70 try: 71 idx = lines.index('set(ALL_CLANG_TIDY_CHECKS\n') 72 lines.insert(idx + 1, ' clangTidyMozillaModule\n') 73 74 with open(cmake_path, 'w') as f: 75 for line in lines: 76 f.write(line) 77 except ValueError: 78 raise Exception('Unable to find ALL_CLANG_TIDY_CHECKS in {}'.format(cmake_path)) 79 80 81def write_third_party_paths(mozilla_path, module_path): 82 tpp_txt = os.path.join( 83 mozilla_path, '../../tools/rewriting/ThirdPartyPaths.txt') 84 generated_txt = os.path.join( 85 mozilla_path, '../../tools/rewriting/Generated.txt') 86 with open(os.path.join(module_path, 'ThirdPartyPaths.cpp'), 'w') as f: 87 ThirdPartyPaths.generate(f, tpp_txt, generated_txt) 88 89 90def generate_thread_allows(mozilla_path, module_path): 91 names = os.path.join( 92 mozilla_path, '../../build/clang-plugin/ThreadAllows.txt' 93 ) 94 files = os.path.join( 95 mozilla_path, '../../build/clang-plugin/ThreadFileAllows.txt' 96 ) 97 with open(os.path.join(module_path, 'ThreadAllows.h'), 'w') as f: 98 f.write(ThreadAllows.generate_allows({files, names})) 99 100 101def do_import(mozilla_path, clang_tidy_path, import_alpha): 102 module = 'mozilla' 103 module_path = os.path.join(clang_tidy_path, module) 104 try: 105 os.makedirs(module_path) 106 except OSError as e: 107 if e.errno != errno.EEXIST: 108 raise 109 110 copy_dir_contents(mozilla_path, module_path) 111 write_third_party_paths(mozilla_path, module_path) 112 generate_thread_allows(mozilla_path, module_path) 113 write_cmake(module_path, import_alpha) 114 add_moz_module(os.path.join(module_path, '..', 'CMakeLists.txt')) 115 with open(os.path.join(module_path, '..', 'CMakeLists.txt'), 'a') as f: 116 f.write('add_subdirectory(%s)\n' % module) 117 # A better place for this would be in `ClangTidyForceLinker.h` but `ClangTidyMain.cpp` 118 # is also OK. 119 with open(os.path.join(module_path, '..', 'tool', 'ClangTidyMain.cpp'), 'a') as f: 120 f.write(''' 121// This anchor is used to force the linker to link the MozillaModule. 122extern volatile int MozillaModuleAnchorSource; 123static int LLVM_ATTRIBUTE_UNUSED MozillaModuleAnchorDestination = 124 MozillaModuleAnchorSource; 125''') 126 127 128def main(): 129 if len(sys.argv) < 3 or len(sys.argv) > 4: 130 print("""\ 131Usage: import_mozilla_checks.py <mozilla-clang-plugin-path> <clang-tidy-path> [import_alpha] 132Imports the Mozilla static analysis checks into a clang-tidy source tree. 133If `import_alpha` is specified then in-tree alpha checkers will be also imported. 134""") 135 136 return 137 138 mozilla_path = sys.argv[1] 139 if not os.path.isdir(mozilla_path): 140 print("Invalid path to mozilla clang plugin") 141 142 clang_tidy_path = sys.argv[2] 143 if not os.path.isdir(mozilla_path): 144 print("Invalid path to clang-tidy source directory") 145 146 import_alpha = False 147 148 if len(sys.argv) == 4 and sys.argv[3] == 'import_alpha': 149 import_alpha = True 150 151 do_import(mozilla_path, clang_tidy_path, import_alpha) 152 153 154if __name__ == '__main__': 155 main() 156