зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1731542 - remove `infer` from our static-analysis pipeline. r=static-analysis-reviewers,marco
Differential Revision: https://phabricator.services.mozilla.com/D126070
This commit is contained in:
Родитель
0873ed43bc
Коммит
e2cab5c39c
2
.flake8
2
.flake8
|
@ -50,7 +50,6 @@ exclude =
|
|||
toolkit/nss.configure,
|
||||
|
||||
# These paths are intentionally excluded (not necessarily for good reason).
|
||||
build/build-infer/build-infer.py,
|
||||
build/moz.configure/*.configure,
|
||||
build/pymake/,
|
||||
browser/extensions/mortar/ppapi/,
|
||||
|
@ -74,7 +73,6 @@ exclude =
|
|||
testing/mozharness/configs/test/test_malformed.py,
|
||||
testing/web-platform/tests,
|
||||
tools/lint/test/files,
|
||||
tools/infer/test/*.configure,
|
||||
tools/crashreporter/*.configure,
|
||||
.ycm_extra_conf.py,
|
||||
|
||||
|
|
|
@ -84,7 +84,6 @@ _OPT\.OBJ/
|
|||
|
||||
# Gradle cache.
|
||||
^.gradle/
|
||||
^tools/infer/test/.gradle/
|
||||
|
||||
# Local Gradle configuration properties.
|
||||
^local.properties$
|
||||
|
@ -192,9 +191,6 @@ tps_result\.json
|
|||
# Ignore Visual Studio Code workspace files.
|
||||
\.vscode/(?!extensions\.json|tasks\.json)
|
||||
|
||||
# Ignore Infer output
|
||||
^infer-out/
|
||||
|
||||
# https://bz.mercurial-scm.org/show_bug.cgi?id=5322
|
||||
^comm/
|
||||
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
build-infer.py
|
||||
==============
|
||||
|
||||
A script to build infer from source.
|
||||
|
||||
```
|
||||
usage: build-infer.py [-h] -c CONFIG [--clean]
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-c CONFIG, --config CONFIG
|
||||
infer configuration file
|
||||
--clean Clean the build directory
|
||||
```
|
||||
|
||||
Pre-requisites
|
||||
--------------
|
||||
* Working build toolchain.
|
||||
* ocam
|
||||
* git
|
||||
* autoconf
|
||||
* libsqlite-dev
|
||||
* CMake
|
||||
* Ninja
|
||||
* Python 2.7
|
||||
|
||||
Please use the latest available CMake for your platform to avoid surprises.
|
||||
|
||||
Config file format
|
||||
------------------
|
||||
|
||||
build-clang.py accepts a JSON config format with the following fields:
|
||||
|
||||
* infer_revision: The infer revision to build.
|
||||
* infer_repo: git repository for infer.
|
||||
* patches: Optional list of patches to apply.
|
|
@ -1,152 +0,0 @@
|
|||
#!/usr/bin/env 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 os
|
||||
import subprocess
|
||||
import json
|
||||
import argparse
|
||||
import sys
|
||||
import shutil
|
||||
from functools import reduce
|
||||
|
||||
|
||||
def check_run(args, path):
|
||||
print(" ".join(args) + " in " + path, file=sys.stderr)
|
||||
subprocess.run(args, cwd=path, check=True)
|
||||
|
||||
|
||||
def run_in(path, args, extra_env=None):
|
||||
"""
|
||||
Runs the given commands in the directory specified by <path>.
|
||||
"""
|
||||
env = dict(os.environ)
|
||||
env.update(extra_env or {})
|
||||
check_run(args, path)
|
||||
subprocess.run(args, cwd=path)
|
||||
|
||||
|
||||
def build_tar_package(tar, name, base, directories):
|
||||
name = os.path.realpath(name)
|
||||
run_in(
|
||||
base,
|
||||
[tar, "-c", "-a", "-f", name] + directories,
|
||||
)
|
||||
|
||||
|
||||
def is_git_repo(dir):
|
||||
"""Check whether the given directory is a git repository."""
|
||||
from subprocess import CalledProcessError
|
||||
|
||||
try:
|
||||
check_run(["git", "rev-parse"], dir)
|
||||
return True
|
||||
except CalledProcessError:
|
||||
return False
|
||||
|
||||
|
||||
def git_clone(main_dir, url, clone_dir, commit):
|
||||
"""
|
||||
Clones the repository from <url> into <clone_dir>, and brings the
|
||||
repository to the state of <commit>.
|
||||
"""
|
||||
run_in(main_dir, ["git", "clone", url, clone_dir])
|
||||
run_in(clone_dir, ["git", "checkout", commit])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--config",
|
||||
required=True,
|
||||
type=argparse.FileType("r"),
|
||||
help="Infer configuration file",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-b", "--base-dir", help="Base directory for code and build artifacts"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--clean", action="store_true", help="Clean the build directory"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--skip-tar", action="store_true", help="Skip tar packaging stage"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# The directories end up in the debug info, so the easy way of getting
|
||||
# a reproducible build is to run it in a know absolute directory.
|
||||
# We use a directory that is registered as a volume in the Docker image.
|
||||
if args.base_dir:
|
||||
base_dir = args.base_dir
|
||||
else:
|
||||
base_dir = reduce(
|
||||
os.path.join, [os.sep + "builds", "worker", "workspace", "moz-toolchain"]
|
||||
)
|
||||
infer_dir = os.path.join(base_dir, "infer")
|
||||
source_dir = os.path.join(infer_dir, "src")
|
||||
build_dir = os.path.join(infer_dir, "build")
|
||||
|
||||
if args.clean:
|
||||
shutil.rmtree(build_dir)
|
||||
os.sys.exit(0)
|
||||
|
||||
config = json.load(args.config)
|
||||
infer_revision = config["infer_revision"]
|
||||
infer_repo = config["infer_repo"]
|
||||
|
||||
for folder in [infer_dir, source_dir, build_dir]:
|
||||
os.makedirs(folder, exist_ok=True)
|
||||
|
||||
# clone infer
|
||||
if not is_git_repo(source_dir):
|
||||
# git doesn't like cloning into a non-empty folder. If src is not a git
|
||||
# repo then just remove it in order to reclone
|
||||
shutil.rmtree(source_dir)
|
||||
git_clone(infer_dir, infer_repo, source_dir, infer_revision)
|
||||
# apply a few patches
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
# clean the git directory by reseting all changes
|
||||
git_commands = [["clean", "-f"], ["reset", "--hard"]]
|
||||
for command in git_commands:
|
||||
run_in(source_dir, ["git"] + command)
|
||||
for p in config.get("patches", []):
|
||||
run_in(source_dir, ["git", "apply", os.path.join(dir_path, p)])
|
||||
# configure opam
|
||||
run_in(source_dir, ["opam", "init", "--no-setup", "--disable-sandboxing"])
|
||||
# build infer
|
||||
run_in(source_dir, ["./build-infer.sh", "java"], extra_env={"NO_CMAKE_STRIP": "1"})
|
||||
|
||||
package_name = "infer"
|
||||
infer_package = os.path.join(os.getcwd(), package_name)
|
||||
# We need to create a package with all of the depended libraries injected in it
|
||||
run_in(
|
||||
source_dir,
|
||||
[
|
||||
"make",
|
||||
"install-with-libs",
|
||||
"BUILD_MODE=opt",
|
||||
"PATCHELF=patchelf",
|
||||
"DESTDIR={}".format(infer_package),
|
||||
"libdir_relative_to_bindir=../lib",
|
||||
],
|
||||
)
|
||||
|
||||
infer_package_with_pref = os.path.join(infer_package, "usr")
|
||||
if not args.skip_tar:
|
||||
os.rename(
|
||||
os.path.join(infer_package_with_pref, "local"),
|
||||
os.path.join(infer_package_with_pref, "infer"),
|
||||
)
|
||||
build_tar_package(
|
||||
"tar",
|
||||
"%s.tar.zst" % (package_name),
|
||||
infer_package_with_pref,
|
||||
[
|
||||
os.path.join("infer", "bin"),
|
||||
os.path.join("infer", "lib"),
|
||||
os.path.join("infer", "share"),
|
||||
],
|
||||
)
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"infer_repo": "https://github.com/facebook/infer",
|
||||
"infer_revision": "99464c01da5809e7159ed1a75ef10f60d34506a4",
|
||||
"patches": []
|
||||
}
|
|
@ -1034,227 +1034,6 @@ class StaticAnalysis(MachCommandBase):
|
|||
|
||||
return commands_list
|
||||
|
||||
@StaticAnalysisSubCommand(
|
||||
"static-analysis", "check-java", "Run infer on the java codebase."
|
||||
)
|
||||
@CommandArgument(
|
||||
"source",
|
||||
nargs="*",
|
||||
default=["mobile"],
|
||||
help="Source files to be analyzed. "
|
||||
"Can be omitted, in which case the entire code base "
|
||||
"is analyzed. The source argument is ignored if "
|
||||
"there is anything fed through stdin, in which case "
|
||||
"the analysis is only performed on the files changed "
|
||||
"in the patch streamed through stdin. This is called "
|
||||
"the diff mode.",
|
||||
)
|
||||
@CommandArgument(
|
||||
"--checks",
|
||||
"-c",
|
||||
default=[],
|
||||
metavar="checks",
|
||||
nargs="*",
|
||||
help="Static analysis checks to enable.",
|
||||
)
|
||||
@CommandArgument(
|
||||
"--jobs",
|
||||
"-j",
|
||||
default="0",
|
||||
metavar="jobs",
|
||||
type=int,
|
||||
help="Number of concurrent jobs to run." " Default is the number of CPUs.",
|
||||
)
|
||||
@CommandArgument(
|
||||
"--task",
|
||||
"-t",
|
||||
type=str,
|
||||
default="compileWithGeckoBinariesDebugSources",
|
||||
help="Which gradle tasks to use to compile the java codebase.",
|
||||
)
|
||||
@CommandArgument(
|
||||
"--outgoing",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Run infer checks on outgoing files from repository",
|
||||
)
|
||||
@CommandArgument("--output", default=None, help="Write infer json output in a file")
|
||||
def check_java(
|
||||
self,
|
||||
command_context,
|
||||
source=["mobile"],
|
||||
jobs=2,
|
||||
strip=1,
|
||||
verbose=False,
|
||||
checks=[],
|
||||
task="compileWithGeckoBinariesDebugSources",
|
||||
skip_export=False,
|
||||
outgoing=False,
|
||||
output=None,
|
||||
):
|
||||
command_context._set_log_level(verbose)
|
||||
command_context.activate_virtualenv()
|
||||
command_context.log_manager.enable_unstructured()
|
||||
|
||||
if command_context.substs["MOZ_BUILD_APP"] != "mobile/android":
|
||||
command_context.log(
|
||||
logging.WARNING,
|
||||
"static-analysis",
|
||||
{},
|
||||
"Cannot check java source code unless you are building for android!",
|
||||
)
|
||||
return 1
|
||||
rc = self._check_for_java(command_context)
|
||||
if rc != 0:
|
||||
return 1
|
||||
if output is not None:
|
||||
output = os.path.abspath(output)
|
||||
if not os.path.isdir(os.path.dirname(output)):
|
||||
command_context.log(
|
||||
logging.WARNING,
|
||||
"static-analysis",
|
||||
{},
|
||||
"Missing report destination folder for {}".format(output),
|
||||
)
|
||||
|
||||
# if source contains the whole mobile folder, then we just have to
|
||||
# analyze everything
|
||||
check_all = any(i.rstrip(os.sep).split(os.sep)[-1] == "mobile" for i in source)
|
||||
# gather all java sources from the source variable
|
||||
java_sources = []
|
||||
if outgoing:
|
||||
repo = get_repository_object(command_context.topsrcdir)
|
||||
java_sources = self._get_java_files(
|
||||
command_context, repo.get_outgoing_files()
|
||||
)
|
||||
if not java_sources:
|
||||
command_context.log(
|
||||
logging.WARNING,
|
||||
"static-analysis",
|
||||
{},
|
||||
"No outgoing Java files to check",
|
||||
)
|
||||
return 0
|
||||
elif not check_all:
|
||||
java_sources = self._get_java_files(command_context, source)
|
||||
if not java_sources:
|
||||
return 0
|
||||
if not skip_export:
|
||||
rc = self._build_export(command_context, jobs=jobs, verbose=verbose)
|
||||
if rc != 0:
|
||||
return rc
|
||||
rc, infer_path = self._get_infer(command_context, verbose=verbose)
|
||||
if rc != 0:
|
||||
command_context.log(
|
||||
logging.WARNING,
|
||||
"static-analysis",
|
||||
{},
|
||||
"This command is only available for linux64!",
|
||||
)
|
||||
return rc
|
||||
# which checkers to use, and which folders to exclude
|
||||
all_checkers, third_party_path, generated_path = self._get_infer_config(
|
||||
command_context
|
||||
)
|
||||
checkers, excludes = self._get_infer_args(
|
||||
checks or all_checkers, third_party_path, generated_path
|
||||
)
|
||||
rc = rc or self._gradle(
|
||||
command_context, ["clean"]
|
||||
) # clean so that we can recompile
|
||||
# infer capture command
|
||||
capture_cmd = [infer_path, "capture"] + excludes + ["--"]
|
||||
rc = rc or self._gradle(
|
||||
command_context, [task], infer_args=capture_cmd, verbose=verbose
|
||||
)
|
||||
tmp_file, args = self._get_infer_source_args(java_sources)
|
||||
# infer analyze command
|
||||
analysis_cmd = [infer_path, "analyze", "--keep-going"] + checkers + args
|
||||
rc = rc or command_context.run_process(
|
||||
args=analysis_cmd, cwd=command_context.topsrcdir, pass_thru=True
|
||||
)
|
||||
if tmp_file:
|
||||
tmp_file.close()
|
||||
|
||||
# Copy the infer report
|
||||
report_path = os.path.join(
|
||||
command_context.topsrcdir, "infer-out", "report.json"
|
||||
)
|
||||
if output is not None and os.path.exists(report_path):
|
||||
shutil.copy(report_path, output)
|
||||
command_context.log(
|
||||
logging.INFO,
|
||||
"static-analysis",
|
||||
{},
|
||||
"Report available in {}".format(output),
|
||||
)
|
||||
|
||||
return rc
|
||||
|
||||
def _get_java_files(self, command_context, sources):
|
||||
java_sources = []
|
||||
for i in sources:
|
||||
f = mozpath.join(command_context.topsrcdir, i)
|
||||
if os.path.isdir(f):
|
||||
for root, dirs, files in os.walk(f):
|
||||
dirs.sort()
|
||||
for file in sorted(files):
|
||||
if file.endswith(".java"):
|
||||
java_sources.append(mozpath.join(root, file))
|
||||
elif f.endswith(".java"):
|
||||
java_sources.append(f)
|
||||
return java_sources
|
||||
|
||||
def _get_infer_source_args(self, sources):
|
||||
"""Return the arguments to only analyze <sources>"""
|
||||
if not sources:
|
||||
return (None, [])
|
||||
# create a temporary file in which we place all sources
|
||||
# this is used by the analysis command to only analyze certain files
|
||||
f = tempfile.NamedTemporaryFile(mode="wt")
|
||||
for source in sources:
|
||||
f.write(source + "\n")
|
||||
f.flush()
|
||||
return (f, ["--changed-files-index", f.name])
|
||||
|
||||
def _get_infer_config(self, command_context):
|
||||
"""Load the infer config file."""
|
||||
checkers = []
|
||||
tp_path = ""
|
||||
with open(
|
||||
mozpath.join(command_context.topsrcdir, "tools", "infer", "config.yaml")
|
||||
) as f:
|
||||
try:
|
||||
config = yaml.safe_load(f)
|
||||
for item in config["infer_checkers"]:
|
||||
if item["publish"]:
|
||||
checkers.append(item["name"])
|
||||
tp_path = mozpath.join(command_context.topsrcdir, config["third_party"])
|
||||
generated_path = mozpath.join(
|
||||
command_context.topsrcdir, config["generated"]
|
||||
)
|
||||
except Exception:
|
||||
print(
|
||||
"Looks like config.yaml is not valid, so we are unable "
|
||||
"to determine default checkers, and which folder to "
|
||||
"exclude, using defaults provided by infer"
|
||||
)
|
||||
return checkers, tp_path, generated_path
|
||||
|
||||
def _get_infer_args(self, checks, *input_paths):
|
||||
"""Return the arguments which include the checkers <checks>, and
|
||||
excludes all folder in <third_party_path>."""
|
||||
checkers = ["-a", "checkers"]
|
||||
excludes = []
|
||||
for checker in checks:
|
||||
checkers.append("--" + checker)
|
||||
for path in input_paths:
|
||||
with open(path) as f:
|
||||
for line in f:
|
||||
excludes.append("--skip-analysis-in-path")
|
||||
excludes.append(line.strip("\n"))
|
||||
return checkers, excludes
|
||||
|
||||
@memoize
|
||||
def get_clang_tidy_config(self, command_context):
|
||||
from mozbuild.code_analysis.utils import ClangTidyConfig
|
||||
|
@ -1407,62 +1186,6 @@ class StaticAnalysis(MachCommandBase):
|
|||
+ sources
|
||||
)
|
||||
|
||||
def _check_for_java(self, command_context):
|
||||
"""Check if javac can be found."""
|
||||
import distutils.spawn
|
||||
|
||||
java = command_context.substs.get("JAVA")
|
||||
java = java or os.getenv("JAVA_HOME")
|
||||
java = java or distutils.spawn.find_executable("javac")
|
||||
error = (
|
||||
"javac was not found! Please install javac and either add it to your PATH, "
|
||||
)
|
||||
error += "set JAVA_HOME, or add the following to your mozconfig:\n"
|
||||
error += " --with-java-bin-path=/path/to/java/bin/"
|
||||
if not java:
|
||||
command_context.log(logging.ERROR, "ERROR: static-analysis", {}, error)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _gradle(
|
||||
self,
|
||||
command_context,
|
||||
args,
|
||||
infer_args=None,
|
||||
verbose=False,
|
||||
autotest=False,
|
||||
suppress_output=True,
|
||||
):
|
||||
infer_args = infer_args or []
|
||||
if autotest:
|
||||
cwd = mozpath.join(command_context.topsrcdir, "tools", "infer", "test")
|
||||
gradle = mozpath.join(cwd, "gradlew")
|
||||
else:
|
||||
gradle = command_context.substs["GRADLE"]
|
||||
cwd = command_context.topsrcdir
|
||||
extra_env = {
|
||||
"GRADLE_OPTS": "-Dfile.encoding=utf-8", # see mobile/android/mach_commands.py
|
||||
"JAVA_TOOL_OPTIONS": "-Dfile.encoding=utf-8",
|
||||
}
|
||||
if suppress_output:
|
||||
devnull = open(os.devnull, "w")
|
||||
return subprocess.call(
|
||||
infer_args + [gradle] + args,
|
||||
env=dict(os.environ, **extra_env),
|
||||
cwd=cwd,
|
||||
stdout=devnull,
|
||||
stderr=subprocess.STDOUT,
|
||||
close_fds=True,
|
||||
)
|
||||
|
||||
return command_context.run_process(
|
||||
infer_args + [gradle] + args,
|
||||
append_env=extra_env,
|
||||
pass_thru=True, # Allow user to run gradle interactively.
|
||||
ensure_exit_code=False, # Don't throw on non-zero exit code.
|
||||
cwd=cwd,
|
||||
)
|
||||
|
||||
@StaticAnalysisSubCommand(
|
||||
"static-analysis",
|
||||
"autotest",
|
||||
|
@ -1731,9 +1454,6 @@ class StaticAnalysis(MachCommandBase):
|
|||
)
|
||||
# Also delete the tmp folder
|
||||
shutil.rmtree(compilation_commands_path)
|
||||
return self._autotest_infer(
|
||||
command_context, dump_results, intree_tool, force_download, verbose
|
||||
)
|
||||
|
||||
def _run_analysis(
|
||||
self,
|
||||
|
@ -1874,207 +1594,6 @@ class StaticAnalysis(MachCommandBase):
|
|||
|
||||
return directory
|
||||
|
||||
def _autotest_infer(
|
||||
self, command_context, dump_results, intree_tool, force_download, verbose
|
||||
):
|
||||
# infer is not available on other platforms, but autotest should work even without
|
||||
# it being installed
|
||||
if command_context.platform[0] == "linux64":
|
||||
rc = self._check_for_java(command_context)
|
||||
if rc != 0:
|
||||
return 1
|
||||
rc, infer_path = self._get_infer(
|
||||
command_context,
|
||||
force=force_download,
|
||||
verbose=verbose,
|
||||
intree_tool=intree_tool,
|
||||
)
|
||||
if rc != 0:
|
||||
command_context.log(
|
||||
logging.ERROR,
|
||||
"ERROR: static-analysis",
|
||||
{},
|
||||
"ERROR: infer unable to locate package.",
|
||||
)
|
||||
return self.TOOLS_FAILED_DOWNLOAD
|
||||
infer_tool = mozpath.join(command_context.topsrcdir, "tools", "infer")
|
||||
infer_test_folder = mozpath.join(infer_tool, "test")
|
||||
|
||||
max_workers = multiprocessing.cpu_count()
|
||||
command_context.log(
|
||||
logging.INFO,
|
||||
"static-analysis",
|
||||
{},
|
||||
"RUNNING: infer autotest for platform {0} with {1} workers.".format(
|
||||
command_context.platform[0], max_workers
|
||||
),
|
||||
)
|
||||
# clean previous autotest if it exists
|
||||
rc = self._gradle(command_context, ["autotest:clean"], autotest=True)
|
||||
if rc != 0:
|
||||
return rc
|
||||
import yaml
|
||||
|
||||
with open(mozpath.join(infer_tool, "config.yaml")) as f:
|
||||
config = yaml.safe_load(f)
|
||||
with concurrent.futures.ThreadPoolExecutor(
|
||||
max_workers=max_workers
|
||||
) as executor:
|
||||
futures = []
|
||||
for item in config["infer_checkers"]:
|
||||
if item["publish"]:
|
||||
futures.append(
|
||||
executor.submit(
|
||||
self._verify_infer_checker,
|
||||
command_context,
|
||||
infer_path,
|
||||
dump_results,
|
||||
infer_tool,
|
||||
infer_test_folder,
|
||||
item,
|
||||
)
|
||||
)
|
||||
# this is always included in check-java, but not in config.yaml
|
||||
futures.append(
|
||||
executor.submit(
|
||||
self._verify_infer_checker,
|
||||
command_context,
|
||||
infer_path,
|
||||
dump_results,
|
||||
infer_tool,
|
||||
infer_test_folder,
|
||||
{"name": "checkers"},
|
||||
)
|
||||
)
|
||||
for future in concurrent.futures.as_completed(futures):
|
||||
ret_val = future.result()
|
||||
if ret_val != self.TOOLS_SUCCESS:
|
||||
return ret_val
|
||||
command_context.log(
|
||||
logging.INFO, "static-analysis", {}, "SUCCESS: infer all tests passed."
|
||||
)
|
||||
else:
|
||||
command_context.log(
|
||||
logging.WARNING,
|
||||
"static-analysis",
|
||||
{},
|
||||
"Skipping infer autotest, because it is only available on linux64!",
|
||||
)
|
||||
return self.TOOLS_SUCCESS
|
||||
|
||||
def _verify_infer_checker(
|
||||
self,
|
||||
command_context,
|
||||
infer_path,
|
||||
dump_results,
|
||||
infer_tool,
|
||||
infer_test_folder,
|
||||
item,
|
||||
):
|
||||
"""Given a checker, this method verifies the following:
|
||||
1. if there is a `checker`.json and `checker`.java file in
|
||||
`tools/infer/test/autotest/src`
|
||||
2. if running infer on `checker`.java yields the same result as `checker`.json
|
||||
An `item` is simply a dictionary, which needs to have a `name` field set, which is the
|
||||
name of the checker.
|
||||
"""
|
||||
|
||||
def to_camelcase(str):
|
||||
return "".join([s.capitalize() for s in str.split("-")])
|
||||
|
||||
check = item["name"]
|
||||
test_file_path = mozpath.join(
|
||||
infer_tool, "test", "autotest", "src", "main", "java", to_camelcase(check)
|
||||
)
|
||||
test_file_path_java = test_file_path + ".java"
|
||||
test_file_path_json = test_file_path + ".json"
|
||||
command_context.log(
|
||||
logging.INFO,
|
||||
"static-analysis",
|
||||
{},
|
||||
"RUNNING: infer check {}.".format(check),
|
||||
)
|
||||
# Verify if the test file exists for this checker
|
||||
if not os.path.exists(test_file_path_java):
|
||||
command_context.log(
|
||||
logging.ERROR,
|
||||
"static-analysis",
|
||||
{},
|
||||
"ERROR: infer check {} doesn't have a test file.".format(check),
|
||||
)
|
||||
return self.TOOLS_CHECKER_NO_TEST_FILE
|
||||
# run infer on a particular test file
|
||||
out_folder = mozpath.join(infer_test_folder, "test-infer-{}".format(check))
|
||||
if check == "checkers":
|
||||
check_arg = ["-a", "checkers"]
|
||||
else:
|
||||
check_arg = ["--{}-only".format(check)]
|
||||
infer_args = [infer_path, "run"] + check_arg + ["-o", out_folder, "--"]
|
||||
gradle_args = ["autotest:compileInferTest{}".format(to_camelcase(check))]
|
||||
rc = self._gradle(
|
||||
command_context, gradle_args, infer_args=infer_args, autotest=True
|
||||
)
|
||||
if rc != 0:
|
||||
command_context.log(
|
||||
logging.ERROR,
|
||||
"static-analysis",
|
||||
{},
|
||||
"ERROR: infer failed to execute gradle {}.".format(gradle_args),
|
||||
)
|
||||
return self.TOOLS_GRADLE_FAILED
|
||||
issues = json.load(open(mozpath.join(out_folder, "report.json")))
|
||||
# remove folder that infer creates because the issues are loaded into memory
|
||||
shutil.rmtree(out_folder)
|
||||
# Verify to see if we got any issues, if not raise exception
|
||||
if not issues:
|
||||
command_context.log(
|
||||
logging.ERROR,
|
||||
"static-analysis",
|
||||
{},
|
||||
"ERROR: infer check "
|
||||
"{0} did not find any issues in its associated test suite.".format(
|
||||
check
|
||||
),
|
||||
)
|
||||
return self.TOOLS_CHECKER_RETURNED_NO_ISSUES
|
||||
if dump_results:
|
||||
self._build_autotest_result(test_file_path_json, json.dumps(issues))
|
||||
else:
|
||||
if not os.path.exists(test_file_path_json):
|
||||
# Result file for test not found maybe regenerate it?
|
||||
command_context.log(
|
||||
logging.ERROR,
|
||||
"static-analysis",
|
||||
{},
|
||||
"ERROR: infer result file not found for check {0}".format(check),
|
||||
)
|
||||
return self.TOOLS_CHECKER_RESULT_FILE_NOT_FOUND
|
||||
# Read the pre-determined issues
|
||||
baseline_issues = self._get_autotest_stored_issues(test_file_path_json)
|
||||
|
||||
def ordered(obj):
|
||||
if isinstance(obj, dict):
|
||||
return sorted((k, ordered(v)) for k, v in obj.items())
|
||||
if isinstance(obj, list):
|
||||
return sorted(ordered(x) for x in obj)
|
||||
return obj
|
||||
|
||||
# Compare the two lists
|
||||
if ordered(issues) != ordered(baseline_issues):
|
||||
error_str = "ERROR: in check {} Expected: ".format(check)
|
||||
error_str += "\n" + json.dumps(baseline_issues, indent=2)
|
||||
error_str += "\n Got:\n" + json.dumps(issues, indent=2)
|
||||
command_context.log(
|
||||
logging.ERROR,
|
||||
"static-analysis",
|
||||
{},
|
||||
"ERROR: infer autotest for check "
|
||||
"{} failed, check stdout for more details".format(check),
|
||||
)
|
||||
print(error_str)
|
||||
return self.TOOLS_CHECKER_DIFF_FAILED
|
||||
return self.TOOLS_SUCCESS
|
||||
|
||||
@StaticAnalysisSubCommand(
|
||||
"static-analysis", "install", "Install the static analysis helper tool"
|
||||
)
|
||||
|
@ -2084,8 +1603,8 @@ class StaticAnalysis(MachCommandBase):
|
|||
type=str,
|
||||
help="Where to fetch a local archive containing the static-analysis and "
|
||||
"format helper tool."
|
||||
"It will be installed in ~/.mozbuild/clang-tools and ~/.mozbuild/infer."
|
||||
"Can be omitted, in which case the latest clang-tools and infer "
|
||||
"It will be installed in ~/.mozbuild/clang-tools."
|
||||
"Can be omitted, in which case the latest clang-tools "
|
||||
"helper for the platform would be automatically detected and installed.",
|
||||
)
|
||||
@CommandArgument(
|
||||
|
@ -2100,35 +1619,22 @@ class StaticAnalysis(MachCommandBase):
|
|||
help="Force re-install even though the tool exists in mozbuild.",
|
||||
default=False,
|
||||
)
|
||||
@CommandArgument(
|
||||
"--minimal-install",
|
||||
action="store_true",
|
||||
help="Download only clang based tool.",
|
||||
default=False,
|
||||
)
|
||||
def install(
|
||||
self,
|
||||
command_context,
|
||||
source=None,
|
||||
skip_cache=False,
|
||||
force=False,
|
||||
minimal_install=False,
|
||||
verbose=False,
|
||||
):
|
||||
command_context._set_log_level(verbose)
|
||||
rc, clang_paths = self._get_clang_tools(
|
||||
rc, _ = self._get_clang_tools(
|
||||
command_context,
|
||||
force=force,
|
||||
skip_cache=skip_cache,
|
||||
source=source,
|
||||
verbose=verbose,
|
||||
)
|
||||
if rc == 0 and not minimal_install:
|
||||
# XXX ignore the return code because if it fails or not, infer is
|
||||
# not mandatory, but clang-tidy is
|
||||
self._get_infer(
|
||||
command_context, force=force, skip_cache=skip_cache, verbose=verbose
|
||||
)
|
||||
return rc
|
||||
|
||||
@StaticAnalysisSubCommand(
|
||||
|
@ -2138,7 +1644,7 @@ class StaticAnalysis(MachCommandBase):
|
|||
)
|
||||
def clear_cache(self, command_context, verbose=False):
|
||||
command_context._set_log_level(verbose)
|
||||
rc, clang_paths = self._get_clang_tools(
|
||||
rc, _ = self._get_clang_tools(
|
||||
command_context,
|
||||
force=True,
|
||||
download_if_needed=True,
|
||||
|
@ -2149,18 +1655,6 @@ class StaticAnalysis(MachCommandBase):
|
|||
if rc != 0:
|
||||
return rc
|
||||
|
||||
job, _ = command_context.platform
|
||||
if job == "linux64":
|
||||
rc, infer_path = self._get_infer(
|
||||
command_context,
|
||||
force=True,
|
||||
download_if_needed=True,
|
||||
skip_cache=True,
|
||||
verbose=verbose,
|
||||
)
|
||||
if rc != 0:
|
||||
return rc
|
||||
|
||||
from mozbuild.atifact_commands import PackageFrontend
|
||||
|
||||
artifact_manager = PackageFrontend(command_context._mach_context)
|
||||
|
@ -2184,24 +1678,7 @@ class StaticAnalysis(MachCommandBase):
|
|||
"-checks=%s" % self.get_clang_tidy_config(command_context).checks,
|
||||
]
|
||||
|
||||
rc = command_context.run_process(args=args, pass_thru=True)
|
||||
if rc != 0:
|
||||
return rc
|
||||
|
||||
job, _ = command_context.platform
|
||||
if job != "linux64":
|
||||
return 0
|
||||
|
||||
rc, infer_path = self._get_infer(command_context, verbose=verbose)
|
||||
if rc != 0:
|
||||
return rc
|
||||
|
||||
checkers, _, _ = self._get_infer_config(command_context)
|
||||
|
||||
print("Infer checks:")
|
||||
for checker in checkers:
|
||||
print(" " * 4 + checker)
|
||||
return 0
|
||||
return command_context.run_process(args=args, pass_thru=True)
|
||||
|
||||
@Command(
|
||||
"prettier-format",
|
||||
|
@ -2922,68 +2399,6 @@ class StaticAnalysis(MachCommandBase):
|
|||
args += [":({0}){1}".format(",".join(magics), pattern)]
|
||||
return args
|
||||
|
||||
def _get_infer(
|
||||
self,
|
||||
command_context,
|
||||
force=False,
|
||||
skip_cache=False,
|
||||
download_if_needed=True,
|
||||
verbose=False,
|
||||
intree_tool=False,
|
||||
):
|
||||
rc, config, _ = self._get_config_environment(command_context)
|
||||
if rc != 0:
|
||||
return rc, ""
|
||||
infer_path = (
|
||||
os.environ["MOZ_FETCHES_DIR"]
|
||||
if intree_tool
|
||||
else mozpath.join(command_context._mach_context.state_dir, "infer")
|
||||
)
|
||||
_infer_path = mozpath.join(
|
||||
infer_path, "infer", "bin", "infer" + config.substs.get("BIN_SUFFIX", "")
|
||||
)
|
||||
if intree_tool:
|
||||
return (not os.path.exists(_infer_path)), _infer_path
|
||||
if os.path.exists(_infer_path) and not force:
|
||||
return 0, _infer_path
|
||||
|
||||
if os.path.isdir(infer_path) and download_if_needed:
|
||||
# The directory exists, perhaps it's corrupted? Delete it
|
||||
# and start from scratch.
|
||||
shutil.rmtree(infer_path)
|
||||
return self._get_infer(
|
||||
command_context,
|
||||
force=force,
|
||||
skip_cache=skip_cache,
|
||||
verbose=verbose,
|
||||
download_if_needed=download_if_needed,
|
||||
)
|
||||
os.mkdir(infer_path)
|
||||
from mozbuild.artifact_commands import PackageFrontend
|
||||
|
||||
artifact_manager = PackageFrontend(command_context._mach_context)
|
||||
if not download_if_needed:
|
||||
return 0, _infer_path
|
||||
job, _ = command_context.platform
|
||||
if job != "linux64":
|
||||
return -1, _infer_path
|
||||
else:
|
||||
job += "-infer"
|
||||
# We want to unpack data in the infer mozbuild folder
|
||||
currentWorkingDir = os.getcwd()
|
||||
os.chdir(infer_path)
|
||||
rc = artifact_manager.artifact_toolchain(
|
||||
command_context,
|
||||
verbose=verbose,
|
||||
skip_cache=skip_cache,
|
||||
from_build=[job],
|
||||
no_unpack=False,
|
||||
retry=0,
|
||||
)
|
||||
# Change back the cwd
|
||||
os.chdir(currentWorkingDir)
|
||||
return rc, _infer_path
|
||||
|
||||
def _run_clang_format_diff(
|
||||
self, command_context, clang_format_diff, clang_format, commit, output_file
|
||||
):
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
# 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/.
|
||||
---
|
||||
job-defaults:
|
||||
# Run only on try and code-review tasks
|
||||
# to avoid running infer on the whole codebase
|
||||
run-on-projects: []
|
||||
platform: linux64/debug
|
||||
worker-type: t-linux-xlarge-source
|
||||
attributes:
|
||||
code-review: true
|
||||
worker:
|
||||
docker-image: {in-tree: android-build}
|
||||
max-run-time: 5400
|
||||
treeherder:
|
||||
kind: other
|
||||
tier: 2
|
||||
run:
|
||||
using: run-task
|
||||
tooltool-downloads: public
|
||||
fetches:
|
||||
toolchain:
|
||||
- linux64-infer
|
||||
- linux64-android-sdk-linux-repack
|
||||
- linux64-android-ndk-linux-repack
|
||||
- linux64-rust-android
|
||||
- linux64-clang
|
||||
- linux64-cbindgen
|
||||
- linux64-nasm
|
||||
- linux64-node
|
||||
when:
|
||||
files-changed:
|
||||
- 'mobile/**/*.java'
|
||||
|
||||
infer:
|
||||
description: Run static-analysis (infer) on Java patches
|
||||
treeherder:
|
||||
symbol: java(infer)
|
||||
run:
|
||||
cwd: '{checkout}'
|
||||
command: >-
|
||||
source taskcluster/scripts/misc/source-test-infer-setup.sh &&
|
||||
./mach --log-no-times configure &&
|
||||
./mach --log-no-times static-analysis check-java --outgoing --output $HOME/infer.json
|
||||
|
||||
worker:
|
||||
artifacts:
|
||||
- type: file
|
||||
name: public/code-review/infer.json
|
||||
path: /builds/worker/infer.json
|
|
@ -23,7 +23,6 @@ jobs-from:
|
|||
- cram.yml
|
||||
- doc.yml
|
||||
- file-metadata.yml
|
||||
- infer.yml
|
||||
- jsshell.yml
|
||||
- mozlint.yml
|
||||
- mozlint-android.yml
|
||||
|
|
|
@ -59,7 +59,6 @@ jobs:
|
|||
toolchain:
|
||||
- linux64-clang
|
||||
- linux64-clang-tidy
|
||||
- linux64-infer
|
||||
- linux64-rust
|
||||
- linux64-sccache
|
||||
- linux64-cbindgen
|
||||
|
|
|
@ -7,23 +7,6 @@ job-defaults:
|
|||
worker:
|
||||
max-run-time: 1800
|
||||
|
||||
linux64-infer:
|
||||
description: "infer build"
|
||||
index:
|
||||
product: static-analysis
|
||||
job-name: linux64-infer
|
||||
treeherder:
|
||||
symbol: TL(infer)
|
||||
worker:
|
||||
docker-image: {in-tree: static-analysis-build}
|
||||
max-run-time: 3600
|
||||
run:
|
||||
script: build-infer-linux.sh
|
||||
resources:
|
||||
- 'build/build-infer/build-infer.py'
|
||||
- 'build/build-infer/infer-linux64.json'
|
||||
toolchain-artifact: public/build/infer.tar.zst
|
||||
|
||||
linux64-binutils-2.31.1:
|
||||
description: "Binutils toolchain build"
|
||||
treeherder:
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -x -e -v
|
||||
|
||||
# This script is for building infer for Linux.
|
||||
|
||||
cd $GECKO_PATH
|
||||
|
||||
# gets a bit too verbose here
|
||||
set +x
|
||||
|
||||
cd build/build-infer
|
||||
./build-infer.py -c infer-linux64.json
|
||||
|
||||
set -x
|
||||
|
||||
# Put a tarball in the artifacts dir
|
||||
mkdir -p $UPLOAD_DIR
|
||||
cp infer.tar.* $UPLOAD_DIR
|
|
@ -1,32 +0,0 @@
|
|||
---
|
||||
target: obj-x86_64-pc-linux-gnu
|
||||
# It is used by 'mach static-analysis' and 'mozreview static-analysis bot'
|
||||
# in order to have consistency across the used checkers.
|
||||
platforms:
|
||||
- linux64
|
||||
infer_checkers:
|
||||
# no issues were ever trigger by this
|
||||
- name: check-nullable
|
||||
publish: !!bool no
|
||||
- name: biabduction
|
||||
publish: !!bool yes
|
||||
# very very noisy
|
||||
# it could be useful, but it won't be part of the default enabled checkers
|
||||
- name: eradicate
|
||||
publish: !!bool no
|
||||
# hard to use, not useful
|
||||
- name: quandary
|
||||
publish: !!bool no
|
||||
- name: starvation
|
||||
publish: !!bool yes
|
||||
# experimental
|
||||
- name: litho
|
||||
publish: !!bool no
|
||||
- name: racerd
|
||||
publish: !!bool yes
|
||||
# I think this is only for c++, can't trigger these errors in Java
|
||||
- name: liveness
|
||||
publish: !!bool no
|
||||
# Third party files from mozilla-central
|
||||
third_party: tools/rewriting/ThirdPartyPaths.txt
|
||||
generated: tools/rewriting/Generated.txt
|
|
@ -1,25 +0,0 @@
|
|||
buildDir "${topobjdir}/gradle/build/tools/infer/test/autotest"
|
||||
|
||||
apply plugin: 'java'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "com.google.code.findbugs:jsr305:3.0.2"
|
||||
}
|
||||
|
||||
def createSingleTask = { name ->
|
||||
task("compileInferTest${name}", type: JavaCompile) {
|
||||
source = fileTree(dir: '.', include: "src/main/java/${name}.java")
|
||||
classpath = project.configurations.compileClasspath
|
||||
destinationDir = file("${topobjdir}/gradle/build/tools/infer/test/autotest")
|
||||
}
|
||||
}
|
||||
|
||||
createSingleTask('Biabduction')
|
||||
createSingleTask('Checkers')
|
||||
createSingleTask('Eradicate')
|
||||
createSingleTask('Racerd')
|
||||
createSingleTask('Starvation')
|
|
@ -1,22 +0,0 @@
|
|||
/* 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 javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
public class Biabduction {
|
||||
private String get() { return null; }
|
||||
|
||||
public void f1() {
|
||||
get().length(); // error
|
||||
}
|
||||
|
||||
public void f2() {
|
||||
try {
|
||||
get().length(); // error
|
||||
} catch (NullPointerException e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
[{"key": "Biabduction.java|f1|NULL_DEREFERENCE", "hash": "18467ae22b3a0dde943dc9dfc84d193a", "severity": "ERROR", "column": -1, "bug_type_hum": "Null Dereference", "node_key": "9afcdcc9d4253c36267a0d34b98c337d", "bug_type": "NULL_DEREFERENCE", "file": "autotest/src/main/java/Biabduction.java", "procedure_start_line": 11, "line": 12, "bug_trace": [{"line_number": 11, "filename": "autotest/src/main/java/Biabduction.java", "description": "start of procedure f1()", "column_number": -1, "level": 0}, {"line_number": 12, "filename": "autotest/src/main/java/Biabduction.java", "description": "", "column_number": -1, "level": 0}, {"line_number": 9, "filename": "autotest/src/main/java/Biabduction.java", "description": "start of procedure get()", "column_number": -1, "level": 1}, {"line_number": 9, "filename": "autotest/src/main/java/Biabduction.java", "description": "return from a call to String Biabduction.get()", "column_number": -1, "level": 1}, {"line_number": 12, "filename": "autotest/src/main/java/Biabduction.java", "description": "", "column_number": -1, "level": 0}], "procedure": "Biabduction.f1():void", "qualifier": "object returned by `get(this)` could be null and is dereferenced at line 12."}, {"key": "Biabduction.java|f2|NULL_DEREFERENCE", "hash": "d2f31f10d3c48ee63c61f52f4f83de4c", "severity": "ERROR", "column": -1, "bug_type_hum": "Null Dereference", "node_key": "9afcdcc9d4253c36267a0d34b98c337d", "bug_type": "NULL_DEREFERENCE", "file": "autotest/src/main/java/Biabduction.java", "procedure_start_line": 15, "line": 17, "bug_trace": [{"line_number": 15, "filename": "autotest/src/main/java/Biabduction.java", "description": "start of procedure f2()", "column_number": -1, "level": 0}, {"line_number": 17, "filename": "autotest/src/main/java/Biabduction.java", "description": "", "column_number": -1, "level": 0}, {"line_number": 9, "filename": "autotest/src/main/java/Biabduction.java", "description": "start of procedure get()", "column_number": -1, "level": 1}, {"line_number": 9, "filename": "autotest/src/main/java/Biabduction.java", "description": "return from a call to String Biabduction.get()", "column_number": -1, "level": 1}, {"line_number": 17, "filename": "autotest/src/main/java/Biabduction.java", "description": "", "column_number": -1, "level": 0}], "procedure": "Biabduction.f2():void", "qualifier": "object returned by `get(this)` could be null and is dereferenced at line 17."}]
|
|
@ -1,34 +0,0 @@
|
|||
/* 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 java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
|
||||
public class Checkers {
|
||||
public static void leak() {
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(
|
||||
new FileReader(new File("some.txt"))
|
||||
);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void error1() {
|
||||
String str = null;
|
||||
try {
|
||||
int x = str.length(); // Error: even if exception is caught
|
||||
} catch (NullPointerException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void error2() {
|
||||
String str = null;
|
||||
int x = str.length(); // Error: not checking for null
|
||||
}
|
||||
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
[{"key": "Checkers.java|leak|RESOURCE_LEAK", "hash": "9c8b2bb1dbffb7893fc2ae9f60f83653", "severity": "ERROR", "column": -1, "bug_type_hum": "Resource Leak", "node_key": "3a2af627d5d1f10e1994f6259cf18e4c", "bug_type": "RESOURCE_LEAK", "file": "autotest/src/main/java/Checkers.java", "procedure_start_line": 10, "line": 12, "bug_trace": [{"line_number": 10, "filename": "autotest/src/main/java/Checkers.java", "description": "start of procedure leak()", "column_number": -1, "level": 0}, {"line_number": 12, "filename": "autotest/src/main/java/Checkers.java", "description": "", "column_number": -1, "level": 0}], "procedure": "Checkers.leak():void", "qualifier": "resource of type `java.io.FileReader` acquired by call to `new()` at line 12 is not released after line 12."}, {"key": "Checkers.java|error1|NULL_DEREFERENCE", "hash": "04ff79bfff8a231ff4cdb045a76641f0", "severity": "ERROR", "column": -1, "bug_type_hum": "Null Dereference", "node_key": "c281f77c6dae544ee5fb7d5e2bb35118", "bug_type": "NULL_DEREFERENCE", "file": "autotest/src/main/java/Checkers.java", "procedure_start_line": 20, "line": 23, "bug_trace": [{"line_number": 20, "filename": "autotest/src/main/java/Checkers.java", "description": "start of procedure error1()", "column_number": -1, "level": 0}, {"line_number": 21, "filename": "autotest/src/main/java/Checkers.java", "description": "", "column_number": -1, "level": 0}, {"line_number": 23, "filename": "autotest/src/main/java/Checkers.java", "description": "", "column_number": -1, "level": 0}], "procedure": "Checkers.error1():void", "qualifier": "object `str` last assigned on line 21 could be null and is dereferenced at line 23."}, {"key": "Checkers.java|error2|NULL_DEREFERENCE", "hash": "c4fe7d68fbb6b3ea84f233de6fd3add8", "severity": "ERROR", "column": -1, "bug_type_hum": "Null Dereference", "node_key": "c281f77c6dae544ee5fb7d5e2bb35118", "bug_type": "NULL_DEREFERENCE", "file": "autotest/src/main/java/Checkers.java", "procedure_start_line": 29, "line": 31, "bug_trace": [{"line_number": 29, "filename": "autotest/src/main/java/Checkers.java", "description": "start of procedure error2()", "column_number": -1, "level": 0}, {"line_number": 30, "filename": "autotest/src/main/java/Checkers.java", "description": "", "column_number": -1, "level": 0}, {"line_number": 31, "filename": "autotest/src/main/java/Checkers.java", "description": "", "column_number": -1, "level": 0}], "procedure": "Checkers.error2():void", "qualifier": "object `str` last assigned on line 30 could be null and is dereferenced at line 31."}]
|
|
@ -1,57 +0,0 @@
|
|||
/* 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 javax.annotation.Nullable;
|
||||
|
||||
// Examples taken from the infer website.
|
||||
public class Eradicate {
|
||||
|
||||
public String f; // Because it is not annoted with nullable -> can never be null!
|
||||
|
||||
public void field(@Nullable Eradicate x) {
|
||||
x.f = "3"; // Error: Eradicate null field access
|
||||
}
|
||||
|
||||
public void method(@Nullable Object x) {
|
||||
String s = x.toString(); // Error: Eradicate null method call
|
||||
}
|
||||
|
||||
public void filedNotNull(@Nullable String s) {
|
||||
f = s; // Error: Eradicate field not nullable
|
||||
}
|
||||
|
||||
public Eradicate() {} // Error: Eradicate field not initialized
|
||||
|
||||
public void str(Eradicate x) {
|
||||
String s = x.toString();
|
||||
}
|
||||
|
||||
public void callStr(@Nullable Eradicate x) {
|
||||
str(x); // Error: Eradicate parameter not nullable
|
||||
}
|
||||
|
||||
public String shouldNotReturnNullBecauseNotAnnotated() {
|
||||
return null; // Error: Eradicate return not nullable
|
||||
}
|
||||
|
||||
public void redundant() {
|
||||
String s = new String("abc");
|
||||
if (s != null) { // Error: Eradicate condition redundant
|
||||
int n = s.length();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String someMethod() {
|
||||
return ""; // Error: Eradicate return overannotated
|
||||
}
|
||||
}
|
||||
|
||||
class B extends Eradicate {
|
||||
@Nullable public String shouldNotReturnNullBecauseNotAnnotated() {
|
||||
return null; // Error: Eradicate inconsistent subclass return annotation
|
||||
}
|
||||
|
||||
public void field(Eradicate x) {} // Error: Inconsistent subclass parameter annotation
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/* 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 javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
// Examples taken from the infer website.
|
||||
@ThreadSafe
|
||||
public class Racerd {
|
||||
private int mTemperature;
|
||||
|
||||
public void makeDinner() {
|
||||
boilWater();
|
||||
}
|
||||
|
||||
private void boilWater() {
|
||||
mTemperature = 100; //Error: unprotected write.
|
||||
}
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
class Account {
|
||||
|
||||
int mBalance = 0;
|
||||
|
||||
public void deposit(int amount) {
|
||||
if (amount > 0) {
|
||||
mBalance += amount; // Error: unsynchronized write
|
||||
}
|
||||
}
|
||||
|
||||
public int withdraw(int amount){
|
||||
if (amount >= 0 && mBalance - amount >= 0) {
|
||||
mBalance -= amount; // Error: unsynchronized write
|
||||
return mBalance; // Error: unsynchronized read
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
[{"key": "Racerd.java|deposit|THREAD_SAFETY_VIOLATION", "hash": "1ec753a9022eedd27443e3ed3da93e44", "severity": "WARNING", "column": -1, "bug_type_hum": "Thread Safety Violation", "access": "hJWmvgAAACsAAAAEAAAAEwAAAA+gsFwA/5IJImF1dG90ZXN0L3NyYy9tYWluL2phdmEvUmFjZXJkLmphdmFA", "bug_type": "THREAD_SAFETY_VIOLATION", "file": "autotest/src/main/java/Racerd.java", "procedure_start_line": 0, "line": 28, "bug_trace": [{"line_number": 28, "filename": "autotest/src/main/java/Racerd.java", "description": "access to `this.mBalance`", "column_number": -1, "level": 0}], "procedure": "Account.deposit(int):void", "qualifier": "Unprotected write. Non-private method `void Account.deposit(int)` writes to field `this.mBalance` outside of synchronization.\n Reporting because the current class is annotated `@ThreadSafe`, so we assume that this method can run in parallel with other non-private methods in the class (including itself)."}, {"key": "Racerd.java|makeDinner|THREAD_SAFETY_VIOLATION", "hash": "b4c48330cdd4742e24fdfc5c809ff604", "severity": "WARNING", "column": -1, "bug_type_hum": "Thread Safety Violation", "access": "hJWmvgAAACsAAAAEAAAAEwAAAA+gsFEA/5IJImF1dG90ZXN0L3NyYy9tYWluL2phdmEvUmFjZXJkLmphdmFA", "bug_type": "THREAD_SAFETY_VIOLATION", "file": "autotest/src/main/java/Racerd.java", "procedure_start_line": 0, "line": 13, "bug_trace": [{"line_number": 13, "filename": "autotest/src/main/java/Racerd.java", "description": "call to void Racerd.boilWater()", "column_number": -1, "level": 0}, {"line_number": 17, "filename": "autotest/src/main/java/Racerd.java", "description": "access to `this.mTemperature`", "column_number": -1, "level": 1}], "procedure": "Racerd.makeDinner():void", "qualifier": "Unprotected write. Non-private method `void Racerd.makeDinner()` indirectly writes to field `this.mTemperature` outside of synchronization.\n Reporting because the current class is annotated `@ThreadSafe`, so we assume that this method can run in parallel with other non-private methods in the class (including itself)."}, {"key": "Racerd.java|withdraw|THREAD_SAFETY_VIOLATION", "hash": "4cb9f0b0b4649ec0f84dea3541a6c70d", "severity": "WARNING", "column": -1, "bug_type_hum": "Thread Safety Violation", "access": "hJWmvgAAADIAAAAGAAAAGgAAABagsGEA/5IJImF1dG90ZXN0L3NyYy9tYWluL2phdmEvUmFjZXJkLmphdmGgsGIA/wQEQA==", "bug_type": "THREAD_SAFETY_VIOLATION", "file": "autotest/src/main/java/Racerd.java", "procedure_start_line": 0, "line": 33, "bug_trace": [{"line_number": 33, "filename": "autotest/src/main/java/Racerd.java", "description": "<Read trace>", "column_number": -1, "level": 0}, {"line_number": 33, "filename": "autotest/src/main/java/Racerd.java", "description": "access to `this.mBalance`", "column_number": -1, "level": 0}, {"line_number": 34, "filename": "autotest/src/main/java/Racerd.java", "description": "<Write trace>", "column_number": -1, "level": 0}, {"line_number": 34, "filename": "autotest/src/main/java/Racerd.java", "description": "access to `this.mBalance`", "column_number": -1, "level": 0}], "procedure": "Account.withdraw(int):int", "qualifier": "Read/Write race. Non-private method `int Account.withdraw(int)` reads without synchronization from `this.mBalance`. Potentially races with write in method `Account.withdraw(...)`.\n Reporting because the current class is annotated `@ThreadSafe`, so we assume that this method can run in parallel with other non-private methods in the class (including itself)."}, {"key": "Racerd.java|withdraw|THREAD_SAFETY_VIOLATION", "hash": "83037b7ad2aa337deba2dbe26e892440", "severity": "WARNING", "column": -1, "bug_type_hum": "Thread Safety Violation", "access": "hJWmvgAAACsAAAAEAAAAEwAAAA+gsGIA/5IJImF1dG90ZXN0L3NyYy9tYWluL2phdmEvUmFjZXJkLmphdmFA", "bug_type": "THREAD_SAFETY_VIOLATION", "file": "autotest/src/main/java/Racerd.java", "procedure_start_line": 0, "line": 34, "bug_trace": [{"line_number": 34, "filename": "autotest/src/main/java/Racerd.java", "description": "access to `this.mBalance`", "column_number": -1, "level": 0}], "procedure": "Account.withdraw(int):int", "qualifier": "Unprotected write. Non-private method `int Account.withdraw(int)` writes to field `this.mBalance` outside of synchronization.\n Reporting because the current class is annotated `@ThreadSafe`, so we assume that this method can run in parallel with other non-private methods in the class (including itself)."}]
|
|
@ -1,25 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
// Examples taken from the infer website.
|
||||
public class Starvation {
|
||||
|
||||
String lockA, lockB;
|
||||
|
||||
public void lockAThenB() {
|
||||
synchronized(lockA) {
|
||||
synchronized(lockB) {
|
||||
// do something with both resources
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void lockBThenA() {
|
||||
synchronized(lockB) {
|
||||
synchronized(lockA) {
|
||||
// do something with both resources
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
[{"key": "Starvation.java|lockAThenB|DEADLOCK", "hash": "9197aca80b5207ae80f4b51c218dcf49", "severity": "ERROR", "column": -1, "bug_type_hum": "Deadlock", "bug_type": "DEADLOCK", "file": "autotest/src/main/java/Starvation.java", "procedure_start_line": 0, "line": 11, "bug_trace": [{"line_number": 11, "filename": "autotest/src/main/java/Starvation.java", "description": "[Trace 1] `void Starvation.lockAThenB()`", "column_number": -1, "level": 0}, {"line_number": 11, "filename": "autotest/src/main/java/Starvation.java", "description": " locks `this.lockA` in `class Starvation`", "column_number": -1, "level": 0}, {"line_number": 12, "filename": "autotest/src/main/java/Starvation.java", "description": " locks `this.lockB` in `class Starvation`", "column_number": -1, "level": 1}, {"line_number": 19, "filename": "autotest/src/main/java/Starvation.java", "description": "[Trace 2] `void Starvation.lockBThenA()`", "column_number": -1, "level": 0}, {"line_number": 19, "filename": "autotest/src/main/java/Starvation.java", "description": " locks `this.lockB` in `class Starvation`", "column_number": -1, "level": 0}, {"line_number": 20, "filename": "autotest/src/main/java/Starvation.java", "description": " locks `this.lockA` in `class Starvation`", "column_number": -1, "level": 1}], "procedure": "Starvation.lockAThenB():void", "qualifier": "Potential deadlock. `void Starvation.lockAThenB()` (Trace 1) and `void Starvation.lockBThenA()` (Trace 2) acquire locks `this.lockB` in `class Starvation` and `this.lockA` in `class Starvation` in reverse orders."}]
|
|
@ -1,6 +0,0 @@
|
|||
allprojects {
|
||||
// Expose the per-object-directory configuration to all projects.
|
||||
ext {
|
||||
topobjdir = gradle.mozconfig.topobjdir
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
org.gradle.parallel=true
|
||||
org.gradle.daemon=true
|
||||
org.gradle.jvmargs=-Xmx2560M
|
Двоичный файл не отображается.
|
@ -1,6 +0,0 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
|
||||
distributionSha256Sum=7a2c66d1a78f811d5f37d14630ad21cec5e77a2a4dc61e787e2257a6341016ce
|
|
@ -1,172 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
|
@ -1,84 +0,0 @@
|
|||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
|
@ -1,24 +0,0 @@
|
|||
// Check out root/settings.gradle for more information
|
||||
|
||||
rootProject.name = 'infer'
|
||||
|
||||
def topsrcdir = rootProject.projectDir.absolutePath + '/../../..'
|
||||
|
||||
def commandLine = ["${topsrcdir}/mach", "environment", "--format", "json", "--verbose"]
|
||||
def proc = commandLine.execute(null, new File(topsrcdir))
|
||||
def standardOutput = new ByteArrayOutputStream()
|
||||
proc.consumeProcessOutput(standardOutput, standardOutput)
|
||||
proc.waitFor()
|
||||
|
||||
if (proc.exitValue() != 0) {
|
||||
throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${proc.exitValue()}:\n\n${standardOutput.toString()}")
|
||||
}
|
||||
|
||||
import groovy.json.JsonSlurper
|
||||
def slurper = new JsonSlurper()
|
||||
def json = slurper.parseText(standardOutput.toString())
|
||||
|
||||
include 'autotest'
|
||||
project(':autotest').projectDir = new File("${json.topsrcdir}/tools/infer/test/autotest")
|
||||
|
||||
gradle.ext.mozconfig = json
|
Загрузка…
Ссылка в новой задаче