# Copyright (C) 2023 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import argparse import os from enum import Enum from collections import defaultdict class Severity(Enum): ENABLED_ERRORS=0 ENABLED_WARNINGS=1 DISABLED_CHECKS=2 def to_flag_string(self): if self == Severity.ENABLED_ERRORS: return "ERROR" elif self == Severity.ENABLED_WARNINGS: return "WARN" else: return "OFF" def extract_error_prone_default_checks_by_severity(filename): """ Args: filename: filename containing the default checks in a version of Errorprone Returns: default_checks: a dictionary representing the Default Errorprone checks, a check_name maps to a severity. """ default_checks = {} with open(filename) as f: lines = f.readlines() current_severity = "" for line in lines: line = line[:-1] if line in [severity.name for severity in Severity]: current_severity = Severity[line] else: default_checks[line] = current_severity return default_checks def get_bazel_compatibility_checks(soong_file, bazel_file): """ Args: soong_file: name of file containing the default checks in the Soong version of Errorprone bazel_file: name of file containing the default checks in the Bazel version of Errorprone Returns: a dictionary representing the checks that need to be modified in Bazel in order for its checks to match Soong's default checks. check_name maps to a severity. """ soong_defaults = extract_error_prone_default_checks_by_severity(soong_file) bazel_defaults= extract_error_prone_default_checks_by_severity(bazel_file) return { check:Severity.DISABLED_CHECKS for check in bazel_defaults if check not in soong_defaults and bazel_defaults[check] != Severity.DISABLED_CHECKS }|{ check:soong_severity for check, soong_severity in soong_defaults.items() if check not in bazel_defaults or soong_severity != bazel_defaults[check] } def check_to_flag_string(check_name, severity): return "-Xep:" + check_name + ":" + severity.to_flag_string() def checks_to_flags(compatibility_checks): """ iterates over items in compatibility_checks dic and returns a dic of the flags using the -Xep:[:severity] format Args: compatibility_checks: output from checks_dic. Returns: severity_to_flag: Dic mapping severities to the command-line flag """ severity_to_flag = defaultdict(list) for check_name, severity in compatibility_checks.items(): severity_to_flag[severity].append(check_to_flag_string(check_name, severity)) for severity in severity_to_flag: severity_to_flag[severity].sort() return severity_to_flag def license_header(): return "# Copyright (C) 2023 The Android Open Source Project\n" \ "#\n" \ "# Licensed under the Apache License, Version 2.0 (the \"License\");\n" \ "# you may not use this file except in compliance with the License.\n" \ "# You may obtain a copy of the License at\n" \ "#\n" \ "# http://www.apache.org/licenses/LICENSE-2.0\n" \ "#\n" \ "# Unless required by applicable law or agreed to in writing, software\n" \ "# distributed under the License is distributed on an \"AS IS\" BASIS,\n" \ "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" \ "# See the License for the specific language governing permissions and\n" \ "# limitations under the License.\n\n" \ def output_as_bzl_file(flags): filename = os.path.dirname(os.path.abspath(__file__)) + "/errorprone_flags.bzl" with open(filename, 'w') as f: f.write(license_header()) f.write("# DO NOT MODIFY: This file is auto-generated by errorProneCompatibilityFlags.sh\n") f.write("errorprone_soong_bazel_diffs = [\n") for severity in Severity: f.write(" # Errorprone {severity}\n".format(severity=severity.name)) for flag in flags[severity]: f.write(" \"{flag}\",\n".format(flag=flag)) f.write("]\n") def main(): parser = argparse.ArgumentParser() parser.add_argument("--soong_file", required=True, help="file containing the default checks in the " "Soong version of Error Prone") parser.add_argument("--bazel_file",required=True, help="file containing the default checks in the" "Bazel version of the Error Prone") args = parser.parse_args() compatibility_checks = get_bazel_compatibility_checks(args.soong_file, args.bazel_file) compatibility_flags = checks_to_flags(compatibility_checks) output_as_bzl_file(compatibility_flags) if __name__ == '__main__': main()