#!/usr/bin/python3
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import errno
import glob
import os
import shutil
import ThirdPartyPaths
import ThreadAllows
def copy_dir_contents(src, dest):
for f
in glob.glob(
"%s/*" % src):
try:
destname =
"%s/%s" % (dest, os.path.basename(f))
if os.path.isdir(f):
shutil.copytree(f, destname)
else:
shutil.copy2(f, destname)
except OSError
as e:
if e.errno == errno.ENOTDIR:
shutil.copy2(f, destname)
elif e.errno == errno.EEXIST:
if os.path.isdir(f):
copy_dir_contents(f, destname)
else:
os.remove(destname)
shutil.copy2(f, destname)
else:
raise Exception(
"Directory not copied. Error: %s" % e)
def write_cmake(module_path, import_options):
names = [
" " + os.path.basename(f)
for f
in glob.glob(
"%s/*.cpp" % module_path)]
if import_options[
"external"]:
names += [
" " + os.path.join(
"external", os.path.basename(f))
for f
in glob.glob(
"%s/external/*.cpp" % (module_path))
]
if import_options[
"alpha"]:
names += [
" " + os.path.join(
"alpha", os.path.basename(f))
for f
in glob.glob(
"%s/alpha/*.cpp" % (module_path))
]
with open(os.path.join(module_path,
"CMakeLists.txt"),
"w")
as f:
f.write(
"""set(LLVM_LINK_COMPONENTS support)
add_definitions( -DCLANG_TIDY )
add_clang_library(clangTidyMozillaModule
ThirdPartyPaths.cpp
%(names)s
LINK_LIBS
clangTidy
clangTidyReadabilityModule
clangTidyUtils
clangTidyMPIModule
)
clang_target_link_libraries(clangTidyMozillaModule
PRIVATE
clangAST
clangASTMatchers
clangBasic
clangLex
)
"""
% {
"names":
"\n".join(names)}
)
def add_moz_module(cmake_path):
with open(cmake_path,
"r")
as f:
lines = f.readlines()
f.close()
try:
idx = lines.index(
"set(ALL_CLANG_TIDY_CHECKS\n")
lines.insert(idx + 1,
" clangTidyMozillaModule\n")
with open(cmake_path,
"w")
as f:
for line
in lines:
f.write(line)
except ValueError:
raise Exception(
"Unable to find ALL_CLANG_TIDY_CHECKS in {}".format(cmake_path))
def write_third_party_paths(mozilla_path, module_path):
tpp_txt = os.path.join(mozilla_path,
"../../tools/rewriting/ThirdPartyPaths.txt")
generated_txt = os.path.join(mozilla_path,
"../../tools/rewriting/Generated.txt")
with open(os.path.join(module_path,
"ThirdPartyPaths.cpp"),
"w")
as f:
ThirdPartyPaths.generate(f, tpp_txt, generated_txt)
def generate_thread_allows(mozilla_path, module_path):
names = os.path.join(mozilla_path,
"../../build/clang-plugin/ThreadAllows.txt")
files = os.path.join(mozilla_path,
"../../build/clang-plugin/ThreadFileAllows.txt")
with open(os.path.join(module_path,
"ThreadAllows.h"),
"w")
as f:
f.write(
ThreadAllows.generate_allows(allowed_names=[names], allowed_files=[files])
)
def do_import(mozilla_path, clang_tidy_path, import_options):
module =
"mozilla"
module_path = os.path.join(clang_tidy_path, module)
try:
os.makedirs(module_path)
except OSError
as e:
if e.errno != errno.EEXIST:
raise
copy_dir_contents(mozilla_path, module_path)
write_third_party_paths(mozilla_path, module_path)
generate_thread_allows(mozilla_path, module_path)
write_cmake(module_path, import_options)
add_moz_module(os.path.join(module_path,
"..",
"CMakeLists.txt"))
with open(os.path.join(module_path,
"..",
"CMakeLists.txt"),
"a")
as f:
f.write(
"add_subdirectory(%s)\n" % module)
# A better place for this would be in `ClangTidyForceLinker.h` but `ClangTidyMain.cpp`
# is also OK.
with open(os.path.join(module_path,
"..",
"tool",
"ClangTidyMain.cpp"),
"a")
as f:
f.write(
"""
// This anchor
is used to force the linker to link the MozillaModule.
extern volatile int MozillaModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED MozillaModuleAnchorDestination =
MozillaModuleAnchorSource;
"""
)
def main():
import argparse
parser = argparse.ArgumentParser(
usage=
"import_mozilla_checks.py [option]",
description=
"Imports the Mozilla static analysis checks into a clang-tidy source tree.",
)
parser.add_argument(
"mozilla_path", help=
"Full path to mozilla-central/build/clang-plugin"
)
parser.add_argument(
"clang_tidy_path", help=
"Full path to llvm-project/clang-tools-extra/clang-tidy"
)
parser.add_argument(
"--import-alpha",
help=
"Enable import of in-tree alpha checks",
action=
"store_true",
)
parser.add_argument(
"--import-external",
help=
"Enable import of in-tree external checks",
action=
"store_true",
)
args = parser.parse_args()
if not os.path.isdir(args.mozilla_path):
print(
"Invalid path to mozilla clang plugin")
if not os.path.isdir(args.clang_tidy_path):
print(
"Invalid path to clang-tidy source directory")
import_options = {
"alpha": args.import_alpha,
"external": args.import_external}
do_import(args.mozilla_path, args.clang_tidy_path, import_options)
if __name__ ==
"__main__":
main()