/*
* Copyright 2016 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.errorprone;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.MaskedClassLoader.MaskedFileManager;
import com.google.errorprone.scanner.ScannerSupplier;
import com.sun.tools.javac.main.CommandLine;
import com.sun.tools.javac.main.Main.Result;
import java.io.BufferedWriter;
import java.io.IOError;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.processing.Processor;
import javax.tools.DiagnosticListener;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
/** An Error Prone compiler that matches the interface of {@link com.sun.tools.javac.Main}. */
public class BaseErrorProneCompiler {
private final DiagnosticListener<? super JavaFileObject> diagnosticListener;
private final PrintWriter errOutput;
private final ScannerSupplier scannerSupplier;
private BaseErrorProneCompiler(
PrintWriter errOutput,
DiagnosticListener<? super JavaFileObject> diagnosticListener,
ScannerSupplier scannerSupplier) {
this.errOutput = errOutput;
this.diagnosticListener = diagnosticListener;
this.scannerSupplier = checkNotNull(scannerSupplier);
}
/** Returns a {@link BaseErrorProneCompiler} builder. */
public static Builder builder() {
return new Builder();
}
/** A {@link BaseErrorProneCompiler} builder. */
public static class Builder {
private DiagnosticListener<? super JavaFileObject> diagnosticListener = null;
private PrintWriter errOutput =
new PrintWriter(
new BufferedWriter(new OutputStreamWriter(System.err, Charset.defaultCharset())), true);
private ScannerSupplier scannerSupplier;
public BaseErrorProneCompiler build() {
return new BaseErrorProneCompiler(errOutput, diagnosticListener, scannerSupplier);
}
public Builder redirectOutputTo(PrintWriter errOutput) {
this.errOutput = errOutput;
return this;
}
public Builder listenToDiagnostics(DiagnosticListener<? super JavaFileObject> listener) {
this.diagnosticListener = listener;
return this;
}
public Builder report(ScannerSupplier scannerSupplier) {
this.scannerSupplier = scannerSupplier;
return this;
}
}
public Result run(String[] argv) {
try {
argv = CommandLine.parse(argv);
} catch (IOException e) {
throw new IOError(e);
}
List<String> javacOpts = new ArrayList<>();
List<String> sources = new ArrayList<>();
for (String arg : argv) {
// TODO(cushon): is there a better way to categorize javacopts?
if (!arg.startsWith("-") && arg.endsWith(".java")) {
sources.add(arg);
} else {
javacOpts.add(arg);
}
}
StandardJavaFileManager fileManager = new MaskedFileManager();
return run(
javacOpts.toArray(new String[0]),
fileManager,
ImmutableList.copyOf(fileManager.getJavaFileObjectsFromStrings(sources)),
null /*processors*/);
}
public Result run(String[] argv, List<JavaFileObject> javaFileObjects) {
return run(argv, null, javaFileObjects, ImmutableList.<Processor>of());
}
public Result run(
String[] args,
JavaFileManager fileManager,
List<JavaFileObject> javaFileObjects,
Iterable<? extends Processor> processors) {
JavaCompiler compiler = new BaseErrorProneJavaCompiler(scannerSupplier);
try {
CompilationTask task =
compiler.getTask(
errOutput,
fileManager,
diagnosticListener,
ImmutableList.copyOf(args),
null /*classes*/,
javaFileObjects);
if (processors != null) {
task.setProcessors(processors);
}
return task.call() ? Result.OK : Result.ERROR;
} catch (InvalidCommandLineOptionException e) {
errOutput.print(e);
errOutput.flush();
return Result.CMDERR;
}
}
}