Skip to content

Commit

Permalink
Move the Error Prone plugin into Bazel
Browse files Browse the repository at this point in the history
--
MOS_MIGRATED_REVID=96365813
  • Loading branch information
cushon authored and damienmg committed Jun 19, 2015
1 parent cda5b66 commit 1ed3c47
Show file tree
Hide file tree
Showing 13 changed files with 242 additions and 82 deletions.
10 changes: 9 additions & 1 deletion examples/java-native/src/main/java/com/example/myproject/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ java_binary(

java_library(
name = "hello-lib",
srcs = glob(["*.java"]),
srcs = glob(
["*.java"],
exclude = ["HelloErrorProne.java"],
),
)

java_binary(
Expand All @@ -23,6 +26,11 @@ java_library(
resources = ["//examples/java-native/src/main/resources:greeting"],
)

java_library(
name = "hello-error-prone",
srcs = ["HelloErrorProne.java"],
)

filegroup(
name = "srcs",
srcs = ["BUILD"] + glob(["**/*.java"]),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.myproject;

/** Sanity check for Error Prone integration. */
public class HelloErrorProne {
public static void main (String[] args) {
boolean result;
byte b = 0;
result = b == 255;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import com.google.devtools.build.buildjar.javac.JavacOptions;
import com.google.devtools.build.buildjar.javac.plugins.BlazeJavaCompilerPlugin;
import com.google.devtools.build.buildjar.javac.plugins.dependency.DependencyModule;
import com.google.devtools.build.buildjar.javac.plugins.errorprone.ErrorProneOptionsPlugin;
import com.google.devtools.build.buildjar.javac.plugins.errorprone.ErrorPronePlugin;
import com.google.devtools.build.buildjar.javac.plugins.filemanager.FileManagerInitializationPlugin;
import com.google.devtools.build.lib.worker.WorkerProtocol.WorkRequest;
import com.google.devtools.build.lib.worker.WorkerProtocol.WorkResponse;
Expand Down Expand Up @@ -125,7 +125,7 @@ private static JavaLibraryBuildRequest parse(List<String> args) throws IOExcepti
ImmutableList<BlazeJavaCompilerPlugin> plugins =
ImmutableList.<BlazeJavaCompilerPlugin>of(
new FileManagerInitializationPlugin(),
new ErrorProneOptionsPlugin());
new ErrorPronePlugin());
JavaLibraryBuildRequest build =
new JavaLibraryBuildRequest(args, plugins, new DependencyModule.Builder());
build.setJavacOpts(JavacOptions.normalizeOptions(build.getJavacOpts()));
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
// 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.

package com.google.devtools.build.buildjar.javac.plugins.errorprone;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.devtools.build.buildjar.InvalidCommandLineException;
import com.google.devtools.build.buildjar.javac.plugins.BlazeJavaCompilerPlugin;
import com.google.errorprone.ErrorProneAnalyzer;
import com.google.errorprone.ErrorProneOptions;
import com.google.errorprone.InvalidCommandLineOptionException;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.scanner.BuiltInCheckerSuppliers;
import com.google.errorprone.scanner.ScannerSupplier;

import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskEvent.Kind;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.main.Main.Result;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.JavacMessages;
import com.sun.tools.javac.util.Log;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ServiceLoader;

import javax.tools.JavaFileManager;
import javax.tools.StandardLocation;

/**
* A plugin for BlazeJavaCompiler that performs Error Prone analysis.
* Error Prone is a static analysis framework that we use to perform
* some simple static checks on Java code.
*/
public final class ErrorPronePlugin extends BlazeJavaCompilerPlugin {

private final Optional<ScannerSupplier> extraChecks;

public ErrorPronePlugin(ScannerSupplier extraChecks) {
this.extraChecks = Optional.of(extraChecks);
}

public ErrorPronePlugin() {
this.extraChecks = Optional.absent();
}

private ErrorProneAnalyzer errorProneAnalyzer;
private ErrorProneOptions epOptions;
// error-prone is enabled by default
private boolean enabled = true;

/** Registers our message bundle. */
public static void setupMessageBundle(Context context) {
JavacMessages.instance(context).add("com.google.errorprone.errors");
}

@Override
public List<String> processArgs(List<String> args) throws InvalidCommandLineException {
// allow javacopts that reference unknown error-prone checks
args = ImmutableList.<String>builder().addAll(args).add("-XepIgnoreUnknownCheckNames").build();
return processEpOptions(processExtraChecksOption(args));
}

private List<String> processEpOptions(List<String> args) throws InvalidCommandLineException {
try {
epOptions = ErrorProneOptions.processArgs(args);
} catch (InvalidCommandLineOptionException e) {
throw new InvalidCommandLineException(e.getMessage());
}
return Arrays.asList(epOptions.getRemainingArgs());
}

private List<String> processExtraChecksOption(List<String> args) {
List<String> arguments = new ArrayList<>();
for (String arg : args) {
switch (arg) {
case "-extra_checks":
case "-extra_checks:on":
enabled = true;
break;
case "-extra_checks:off":
enabled = false;
break;
default:
arguments.add(arg);
}
}
return arguments;
}

private ScannerSupplier defaultScannerSupplier() {
// open-source checks that are errors
ScannerSupplier result = BuiltInCheckerSuppliers.errorChecks();
if (extraChecks.isPresent()) {
result = result.plus(extraChecks.get());
}
return result;
}

private static final Function<BugChecker, Class<? extends BugChecker>> GET_CLASS =
new Function<BugChecker, Class<? extends BugChecker>>() {
@Override
public Class<? extends BugChecker> apply(BugChecker input) {
return input.getClass();
}
};

@Override
public void init(Context context, Log log, JavaCompiler compiler) {
super.init(context, log, compiler);

if (!enabled) { // error-prone plugin is turned-off
return;
}

setupMessageBundle(context);

// TODO(cushon): Move this into error-prone proper
JavaFileManager fileManager = context.get(JavaFileManager.class);
// Search ANNOTATION_PROCESSOR_PATH if it's available, otherwise fallback to fileManager's
// own class loader. Unlike in annotation processor discovery, we never search CLASS_PATH.
ClassLoader loader = fileManager.hasLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH)
? fileManager.getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_PATH)
: fileManager.getClass().getClassLoader();
Iterable<BugChecker> extraBugCheckers = ServiceLoader.load(BugChecker.class, loader);
ScannerSupplier scannerSupplier =
defaultScannerSupplier().plus(
ScannerSupplier.fromBugCheckerClasses(
Iterables.transform(extraBugCheckers, GET_CLASS)));

if (epOptions != null) {
try {
scannerSupplier = scannerSupplier.applyOverrides(epOptions);
} catch (InvalidCommandLineOptionException e) {
throwError(Result.CMDERR, e.getMessage());
}
}

errorProneAnalyzer = ErrorProneAnalyzer.create(scannerSupplier.get()).init(context);
}

/**
* Run Error Prone analysis after performing dataflow checks.
*/
@Override
public void postFlow(Env<AttrContext> env) {
if (enabled) {
errorProneAnalyzer.finished(new TaskEvent(Kind.ANALYZE, env.toplevel, env.enclClass.sym));
}
}

@VisibleForTesting
public boolean isEnabled() {
return enabled;
}
}
11 changes: 0 additions & 11 deletions src/main/tools/jdk.BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,3 @@ filegroup(
name = "jdk-default",
srcs = glob(["bin/*"]),
)

filegroup(
name = "langtools",
srcs = ["lib/tools.jar"],
)

java_import(
name = "langtools-neverlink",
jars = ["lib/tools.jar"],
neverlink = 1,
)
1 change: 1 addition & 0 deletions src/test/shell/bazel/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ filegroup(
"//src/test/shell:bashunit",
"//third_party:srcs",
"//third_party/ijar",
"//third_party/java/jdk/langtools:srcs",
"//tools:srcs",
],
)
Expand Down
5 changes: 4 additions & 1 deletion src/test/shell/bazel/bazel_example_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ function test_java() {
function test_java_test() {
setup_javatest_support
local java_native_tests=//examples/java-native/src/test/java/com/example/myproject
local java_native_main=//examples/java-native/src/main/java/com/example/myproject

assert_build //examples/java-native/...
assert_build "-- //examples/java-native/... -${java_native_main}:hello-error-prone"
assert_build_fails "${java_native_main}:hello-error-prone" \
"Did you mean 'result = b == -1;'?"
assert_test_ok "${java_native_tests}:hello"
assert_test_ok "${java_native_tests}:custom"
assert_test_fails "${java_native_tests}:fail"
Expand Down
13 changes: 13 additions & 0 deletions src/test/shell/bazel/test-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,13 @@ function create_new_workspace() {
workspaces+=(${new_workspace_dir})
cd ${new_workspace_dir}
mkdir tools
mkdir -p third_party/java/jdk/langtools

copy_tools_directory

[ -e third_party/java/jdk/langtools/javac.jar ] \
|| ln -s "${langtools_path}" third_party/java/jdk/langtools/javac.jar

ln -s "${javabuilder_path}" tools/jdk/JavaBuilder_deploy.jar
ln -s "${singlejar_path}" tools/jdk/SingleJar_deploy.jar
ln -s "${ijar_path}" tools/jdk/ijar
Expand Down Expand Up @@ -179,6 +183,15 @@ function assert_build_output() {
test -f "$OUTPUT" || fail "Output $OUTPUT not found for target $*"
}

function assert_build_fails() {
bazel build -s $1 >& $TEST_log \
&& fail "Test $1 succeed while expecting failure" \
|| true
if [ -n "${2:-}" ]; then
expect_log "$2"
fi
}

function assert_test_ok() {
bazel test --test_output=errors $* \
|| fail "Test $1 failed while expecting success"
Expand Down
7 changes: 6 additions & 1 deletion src/test/shell/bazel/testenv.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ langtools="${TEST_SRCDIR}/src/test/shell/bazel/langtools.jar"

# Tools directory location
tools_dir="${TEST_SRCDIR}/tools"
langtools_dir="${TEST_SRCDIR}/third_party/java/jdk/langtools"
EXTRA_BAZELRC="build --java_langtools=//tools/jdk:test-langtools"

# Java tooling
javabuilder_path="${TEST_SRCDIR}/src/java_tools/buildjar/JavaBuilder_deploy.jar"
langtools_path="${TEST_SRCDIR}/third_party/java/jdk/langtools/javac.jar"
singlejar_path="${TEST_SRCDIR}/src/java_tools/singlejar/SingleJar_deploy.jar"
ijar_path="${TEST_SRCDIR}/third_party/ijar/ijar"

Expand Down Expand Up @@ -77,6 +79,9 @@ function copy_tools_directory() {
filegroup(name = "test-langtools", srcs = ["langtools.jar"])
EOF

mkdir -p third_party/java/jdk/langtools
cp -R ${langtools_dir}/* third_party/java/jdk/langtools

chmod -R +w .
mkdir -p tools/defaults
touch tools/defaults/BUILD
Expand All @@ -85,7 +90,7 @@ EOF
# Report whether a given directory name corresponds to a tools directory.
function is_tools_directory() {
case "$1" in
tools)
third_party|tools)
true
;;
*)
Expand Down
Loading

0 comments on commit 1ed3c47

Please sign in to comment.