package bluej.compiler;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import bluej.Config;
import bluej.compiler.Diagnostic.DiagnosticOrigin;
| A compiler implementation using the Compiler API introduced in Java 6.
|
| @author Marion Zalk
|
public class CompilerAPICompiler
extends Compiler{
private static final AtomicInteger nextDiagnosticIdentifier = new AtomicInteger(1);
public CompilerAPICompiler()
{
setDebug(true);
setDeprecation(true);
}
| Compile some source files by using the JavaCompiler API. Allows for the addition of user
| options
|
| @param sources
| The files to compile
| @param observer
| The compilation observer
| @param internal
| True if compiling BlueJ-generated code (shell files); false if
| compiling user code
|
| @return true if successful
|
@Override
public boolean compile(final File[] sources, final CompileObserver observer,
final boolean internal, List<String> userOptions, Charset fileCharset, CompileType type)
{
boolean result = true;
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
List<String> optionsList = new ArrayList<String>();
if (jc == null) {
observer.compilerMessage(new bluej.compiler.Diagnostic(bluej.compiler.Diagnostic.ERROR,
"The compiler does not appear to be available."), type);
return false;
}
DiagnosticListener<JavaFileObject> diagListener = new DiagnosticListener<JavaFileObject>() {
@Override
public void report(Diagnostic<? extends JavaFileObject> diag)
{
String src = null;
if (diag.getSource() != null)
{
if (Config.isJava17()) {
src = diag.getSource().getName();
}
else {
URI srcUri = sources[0].toURI().resolve(diag.getSource().toUri());
src = new File(srcUri).getPath();
}
}
int diagType;
bluej.compiler.Diagnostic bjDiagnostic;
String message = diag.getMessage(null);
if (diag.getKind() == Diagnostic.Kind.ERROR) {
diagType = bluej.compiler.Diagnostic.ERROR;
message = processMessage(src, (int) diag.getLineNumber(), message);
long beginCol = diag.getColumnNumber();
long endCol = diag.getEndPosition() - diag.getPosition() + beginCol;
if (diag.getEndPosition() == Diagnostic.NOPOS) {
endCol = beginCol;
}
if (diag.getLineNumber() == -1)
bjDiagnostic = null;
else{ bjDiagnostic = new bluej.compiler.Diagnostic(diagType,
message, src, diag.getLineNumber(), beginCol,
diag.getLineNumber(), endCol, DiagnosticOrigin.JAVAC, getNewErrorIdentifer());
}
}
else if (diag.getKind() == Diagnostic.Kind.WARNING) {
if (message.startsWith("bootstrap class path not set in conjunction with -source ")) {
return;
}
if (message.startsWith("未与 -source") && message.endsWith("一起设置引导类路径")) {
return;
}
if (message.startsWith("ブートストラップ・クラスパスが-source") && message.endsWith("一緒に設定されていません")){
return;
}
diagType = bluej.compiler.Diagnostic.WARNING;
long beginCol = diag.getColumnNumber();
long endCol = diag.getEndPosition() - diag.getPosition() + beginCol;
bjDiagnostic = new bluej.compiler.Diagnostic(diagType,
message, src, diag.getLineNumber(), beginCol,
diag.getLineNumber(), endCol, DiagnosticOrigin.JAVAC, getNewErrorIdentifer());
}
else {
diagType = bluej.compiler.Diagnostic.NOTE;
bjDiagnostic = new bluej.compiler.Diagnostic(diagType, message);
if (internal &&
(message.endsWith(" uses unchecked or unsafe operations.") ||
message.endsWith("Some input files use unchecked or unsafe operations.") ||
message.endsWith("Recompile with -Xlint:unchecked for details."))) {
return;
}
}
if (bjDiagnostic != null)
observer.compilerMessage(bjDiagnostic, type);
}
};
try
{
StandardJavaFileManager sjfm = jc.getStandardFileManager(diagListener, null, fileCharset);
List<File> pathList = new ArrayList<File>();
List<File> outputList = new ArrayList<File>();
outputList.add(getDestDir());
pathList.addAll(getClassPath());
sjfm.setLocation(StandardLocation.SOURCE_PATH, outputList);
sjfm.setLocation(StandardLocation.CLASS_PATH, pathList);
File tempDir = null;
if (type.keepClasses())
{
sjfm.setLocation(StandardLocation.CLASS_OUTPUT, outputList);
}
else
{
tempDir = Files.createTempDirectory("bluej").toFile();
sjfm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(tempDir));
}
Iterable<? extends JavaFileObject> compilationUnits1 =
sjfm.getJavaFileObjectsFromFiles(Arrays.asList(sources));
if (isDebug()) {
optionsList.add("-g");
}
if (isDeprecation()) {
optionsList.add("-deprecation");
}
File[] bootClassPath = getBootClassPath();
if (bootClassPath != null && bootClassPath.length != 0) {
sjfm.setLocation(StandardLocation.PLATFORM_CLASS_PATH, Arrays.asList(bootClassPath));
}
optionsList.addAll(userOptions);
result = jc.getTask(null, sjfm, diagListener, optionsList, null, compilationUnits1).call();
sjfm.close();
if (tempDir != null)
tempDir.delete();
}
catch(IOException e)
{
e.printStackTrace(System.out);
return false;
}
return result;
}
| Processes messages returned from the compiler. This just slightly adjusts the format of some
| messages.
|
| @param src The source file path
| @param pos The line number at which the error occurrs
| @param message The error message
|
protected String processMessage(String src, int pos, String message)
{
String expected = src + ":" + pos + ": ";
if (message.startsWith(expected))
{
message = message.substring(expected.length());
}
if (message.contains("cannot resolve symbol")
|| message.contains("cannot find symbol")
|| message.contains("incompatible types"))
{
int index1, index2;
String line2, line3;
index1 = message.indexOf('\n');
if (index1 == -1)
{
return message;
}
index2 = message.indexOf('\n',index1+1);
if (index2 < index1)
{
line2 = message.substring(index1).trim();
line3 = "";
}
else {
line2 = message.substring(index1, index2).trim();
line3 = message.substring(index2).trim();
}
message = message.substring(0, index1);
if (line2.startsWith("found") && line2.indexOf(':') != -1)
{
message = message +" - found " + line2.substring(line2.indexOf(':') + 2, line2.length());
}
if (line3.startsWith("required") && line3.indexOf(':') != -1) {
message = message +" but expected " + line3.substring(line3.indexOf(':') + 2, line3.length());
}
if (line2.startsWith("symbol") && line2.indexOf(':') != -1)
{
message = message + " - " + line2.substring(line2.indexOf(':') + 2, line2.length());
}
}
return message;
}
public static int getNewErrorIdentifer()
{
return nextDiagnosticIdentifier.getAndIncrement();
}
}
top,
use,
map,
class CompilerAPICompiler
. CompilerAPICompiler
. compile
. report
. processMessage
. getNewErrorIdentifer
336 neLoCode
+ 17 LoComm