Merge pull request #4042 from JakubValtar/error-checker-update

Error checker update
This commit is contained in:
Ben Fry
2015-10-22 11:29:57 -04:00
5 changed files with 196 additions and 617 deletions
@@ -1296,9 +1296,9 @@ public class JavaEditor extends Editor {
public void internalCloseRunner() {
// Added temporarily to dump error log. TODO: Remove this later [mk29]
if (JavaMode.errorLogsEnabled) {
writeErrorsToFile();
}
//if (JavaMode.errorLogsEnabled) {
// writeErrorsToFile();
//}
handleStop();
}
@@ -1328,10 +1328,12 @@ public class JavaEditor extends Editor {
}
// Not sure how this was supposed to work, tempErrorLog is always empty [jv]
/**
* Writes all error messages to a csv file.
* For analytics purposes only.
*/
/*
private void writeErrorsToFile() {
if (errorCheckerService.tempErrorLog.size() == 0) return;
@@ -1369,7 +1371,7 @@ public class JavaEditor extends Editor {
System.err.println("Failed to save log file for sketch " + getSketch().getName());
e.printStackTrace();
}
}
}*/
/*
@@ -216,8 +216,7 @@ public class ASTGenerator {
Map<String, String> options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, options);
options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8);
JavaCore.setComplianceOptions(JavaCore.VERSION_1_7, options);
parser.setCompilerOptions(options);
compilationUnit = (CompilationUnit) parser.createAST(null);
} else {
@@ -343,7 +342,7 @@ public class ASTGenerator {
}
jdocMap.put(methodName, msg);
}
System.out.println("JDoc loaded " + jdocMap.size());
//System.out.println("JDoc loaded " + jdocMap.size());
}
@@ -1523,7 +1522,7 @@ public class ASTGenerator {
} else if (parent instanceof Block) {
nodes = ((Block) parent).statements();
} else {
System.err.println("findClosestNode() found " + getNodeAsString(parent));
log("findClosestNode() found " + getNodeAsString(parent));
return null;
}
@@ -1,501 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2012-15 The Processing Foundation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package processing.mode.java.pdex;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ClassFile;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.Compiler;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jface.text.Document;
/**
* Provides compilation checking functionality
* @author Manindra Moharana &lt;me@mkmoharana.com&gt;
*/
public class CompilationChecker {
private class CompilationUnitImpl implements ICompilationUnit {
private CompilationUnit unit;
CompilationUnitImpl(CompilationUnit unit) {
this.unit = unit;
}
public char[] getContents() {
char[] contents = null;
try {
Document doc = new Document();
doc.set(sourceText);
// TextEdit edits = unit.rewrite(doc, null);
// edits.apply(doc);
String sourceCode = doc.get();
if (sourceCode != null)
contents = sourceCode.toCharArray();
} catch (Exception e) {
throw new RuntimeException(e);
}
return contents;
}
public char[] getMainTypeName() {
TypeDeclaration classType = (TypeDeclaration) unit.types().get(0);
return classType.getName().getFullyQualifiedName().toCharArray();
}
public char[][] getPackageName() {
String[] names = getSimpleNames(this.unit.getPackage().getName()
.getFullyQualifiedName());
char[][] packages = new char[names.length][];
for (int i = 0; i < names.length; ++i)
packages[i] = names[i].toCharArray();
return packages;
}
public char[] getFileName() {
TypeDeclaration classType = (TypeDeclaration) unit.types().get(0);
String name = classType.getName().getFullyQualifiedName() + ".java";
return name.toCharArray();
}
@Override
public boolean ignoreOptionalProblems() {
return false;
}
}
/**
* ICompilerRequestor implementation
*/
private class CompileRequestorImpl implements ICompilerRequestor {
private List<IProblem> problems;
private List<ClassFile> classes;
public CompileRequestorImpl() {
this.problems = new ArrayList<IProblem>();
this.classes = new ArrayList<ClassFile>();
}
public void acceptResult(CompilationResult result) {
boolean errors = false;
if (result.hasProblems()) {
IProblem[] problems = result.getProblems();
for (int i = 0; i < problems.length; i++) {
if (problems[i].isError())
errors = true;
this.problems.add(problems[i]);
}
}
if (!errors) {
ClassFile[] classFiles = result.getClassFiles();
for (int i = 0; i < classFiles.length; i++)
this.classes.add(classFiles[i]);
}
}
List<IProblem> getProblems() {
return this.problems;
}
// List<ClassFile> getResults() {
// //System.out.println("Calling get results");
// return this.classes;
// }
}
/**
* INameEnvironment implementation
*/
private class NameEnvironmentImpl implements INameEnvironment {
private ICompilationUnit unit;
private String fullName;
NameEnvironmentImpl(ICompilationUnit unit) {
this.unit = unit;
this.fullName = CharOperation.toString(this.unit.getPackageName()) + "."
+ new String(this.unit.getMainTypeName());
}
public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
return findType(CharOperation.toString(compoundTypeName));
}
public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
String fullName = CharOperation.toString(packageName);
if (typeName != null) {
if (fullName.length() > 0)
fullName += ".";
fullName += new String(typeName);
}
return findType(fullName);
}
public boolean isPackage(char[][] parentPackageName, char[] packageName) {
String fullName = CharOperation.toString(parentPackageName);
if (packageName != null) {
if (fullName.length() > 0)
fullName += ".";
fullName += new String(packageName);
}
if (findType(fullName) != null)
return false;
try {
return (getClassLoader().loadClass(fullName) == null);
} catch (ClassNotFoundException e) {
return true;
}
}
public void cleanup() {
}
private NameEnvironmentAnswer findType(String fullName) {
if (this.fullName.equals(fullName))
return new NameEnvironmentAnswer(unit, null);
try {
InputStream is = getClassLoader().getResourceAsStream(fullName
.replace('.',
'/')
+ ".class");
if (is != null) {
// System.out.println("Find type: " + fullName);
byte[] buffer = new byte[8192];
int bytes = 0;
ByteArrayOutputStream os = new ByteArrayOutputStream(buffer.length);
while ((bytes = is.read(buffer, 0, buffer.length)) > 0)
os.write(buffer, 0, bytes);
os.flush();
ClassFileReader classFileReader = new ClassFileReader(
os.toByteArray(),
fullName
.toCharArray(),
true);
return new NameEnvironmentAnswer(classFileReader, null);
}
return null;
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassFormatException e) {
throw new RuntimeException(e);
}
}
}
private URLClassLoader urlClassLoader;
private ClassLoader getClassLoader() {
if (urlClassLoader != null) {
return urlClassLoader;
} else {
return getClass().getClassLoader();
}
}
private void prepareClassLoader(ArrayList<File> jarList) {
URL urls[] = new URL[jarList.size()];
for (int i = 0; i < urls.length; i++) {
try {
urls[i] = jarList.get(i).toURI().toURL();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
urlClassLoader = new URLClassLoader(urls);
//System.out.println("URL Classloader ready");
}
/**
* ClassLoader implementation
*/
/*
private class CustomClassLoader extends ClassLoader {
private Map classMap;
CustomClassLoader(ClassLoader parent, List classesList) {
this.classMap = new HashMap();
for (int i = 0; i < classesList.size(); i++) {
ClassFile classFile = (ClassFile) classesList.get(i);
String className = CharOperation.toString(classFile.getCompoundName());
this.classMap.put(className, classFile.getBytes());
}
}
public Class findClass(String name) throws ClassNotFoundException {
byte[] bytes = (byte[]) this.classMap.get(name);
if (bytes != null)
return defineClass(name, bytes, 0, bytes.length);
return super.findClass(name);
}
};
*/
@SuppressWarnings("unchecked")
private ICompilationUnit generateCompilationUnit() {
ASTParser parser = ASTParser.newParser(AST.JLS8);
try {
parser.setSource("".toCharArray());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Map<String, String> options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, options);
parser.setCompilerOptions(options);
CompilationUnit unit = (CompilationUnit) parser.createAST(null);
unit.recordModifications();
AST ast = unit.getAST();
// Package statement
// package astexplorer;
PackageDeclaration packageDeclaration = ast.newPackageDeclaration();
unit.setPackage(packageDeclaration);
// unit.se
packageDeclaration.setName(ast.newSimpleName(fileName));
// System.out.println("Filename: " + fileName);
// class declaration
// public class SampleComposite extends Composite {
TypeDeclaration classType = ast.newTypeDeclaration();
classType.setInterface(false);
// classType.s
classType.setName(ast.newSimpleName(fileName));
unit.types().add(classType);
// classType.setSuperclass(ast.newSimpleName("Composite"));
return new CompilationUnitImpl(unit);
}
static private String fileName = null; //"HelloPeasy";
private void compileMeQuitely(ICompilationUnit unit, Map<String, String> compilerSettings) {
Map<String, String> settings;
if (compilerSettings == null) {
settings = new HashMap<>();
settings.put(CompilerOptions.OPTION_LineNumberAttribute,
CompilerOptions.GENERATE);
settings.put(CompilerOptions.OPTION_SourceFileAttribute,
CompilerOptions.GENERATE);
settings.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_6);
settings.put(CompilerOptions.OPTION_SuppressWarnings,
CompilerOptions.DISABLED);
// settings.put(CompilerOptions.OPTION_ReportUnusedImport,
// CompilerOptions.IGNORE);
// settings.put(CompilerOptions.OPTION_ReportMissingSerialVersion,
// CompilerOptions.IGNORE);
// settings.put(CompilerOptions.OPTION_ReportRawTypeReference,
// CompilerOptions.IGNORE);
// settings.put(CompilerOptions.OPTION_ReportUncheckedTypeOperation,
// CompilerOptions.IGNORE);
} else {
settings = compilerSettings;
}
// CompilerOptions cop = new CompilerOptions();
// cop.set(settings);
CompileRequestorImpl requestor = new CompileRequestorImpl();
Compiler compiler = new Compiler(new NameEnvironmentImpl(unit),
DefaultErrorHandlingPolicies
.proceedWithAllProblems(),
new CompilerOptions(settings), requestor,
new DefaultProblemFactory(Locale
.getDefault()));
compiler.compile(new ICompilationUnit[] { unit });
List<IProblem> problems = requestor.getProblems();
prob = new IProblem[problems.size()];
int count = 0;
for (Iterator<IProblem> it = problems.iterator(); it.hasNext();) {
IProblem problem = it.next();
prob[count++] = problem;
}
}
private void compileMeQuitely(ICompilationUnit unit) {
compileMeQuitely(unit, null);
}
static private String[] getSimpleNames(String qualifiedName) {
StringTokenizer st = new StringTokenizer(qualifiedName, ".");
ArrayList<String> list = new ArrayList<String>();
while (st.hasMoreTokens()) {
String name = st.nextToken().trim();
if (!name.equals("*"))
list.add(name);
}
return list.toArray(new String[0]);
}
public static void main(String[] args) {
ArrayList<File> fl = new ArrayList<File>();
fl.add(new File(
"/home/quarkninja/Workspaces/processing_workspace/processing/core/library/core.jar"));
CompilationChecker cc = new CompilationChecker(fl);
cc.getErrors("Brightness");
cc.display();
}
public void display() {
boolean error = false;
int errorCount = 0, warningCount = 0, count = 0;
for (int i = 0; i < prob.length; i++) {
IProblem problem = prob[i];
if (problem == null)
continue;
StringBuilder sb = new StringBuilder();
sb.append(problem.getMessage());
sb.append(" | line: ");
sb.append(problem.getSourceLineNumber());
String msg = sb.toString();
if (problem.isError()) {
error = true;
msg = "Error: " + msg;
errorCount++;
} else if (problem.isWarning()) {
msg = "Warning: " + msg;
warningCount++;
}
System.out.println(msg);
prob[count++] = problem;
}
if (!error) {
System.out.println("====================================");
System.out.println(" Compiled without any errors. ");
System.out.println("====================================");
} else {
System.out.println("====================================");
System.out.println(" Compilation failed. You erred man! ");
System.out.println("====================================");
}
System.out.print("Total warnings: " + warningCount);
System.out.println(", Total errors: " + errorCount);
}
IProblem[] prob;
public IProblem[] getErrors(String name) {
fileName = name;
compileMeQuitely(generateCompilationUnit());
// System.out.println("getErrors()");
return prob;
}
/**
* Performs compiler error check.
* @param sourceName - name of the class
* @param source - source code
* @param settings - compiler options
* @param classLoader - custom classloader which can load all dependencies
* @return IProblem[] - list of compiler errors and warnings
*/
public IProblem[] getErrors(String sourceName, String source, Map<String, String> settings,
URLClassLoader classLoader) {
fileName = sourceName;
sourceText = "package " + fileName + ";\n" + source;
if (classLoader != null)
this.urlClassLoader = classLoader;
compileMeQuitely(generateCompilationUnit(), settings);
// System.out.println("getErrors(), Done.");
return prob;
}
String sourceText = null; //"";
public IProblem[] getErrors(String sourceName, String source) {
return getErrors(sourceName, source, null);
}
public IProblem[] getErrors(String sourceName, String source, Map<String, String> settings) {
fileName = sourceName;
sourceText = "package " + fileName + ";\n" + source;
compileMeQuitely(generateCompilationUnit(), settings);
// System.out.println("getErrors(), Done.");
return prob;
}
public CompilationChecker() {
// System.out.println("Compilation Checker initialized.");
}
public CompilationChecker(ArrayList<File> fileList) {
prepareClassLoader(fileList);
// System.out.println("Compilation Checker initialized.");
}
}
@@ -21,16 +21,20 @@ along with this program; if not, write to the Free Software Foundation, Inc.
package processing.mode.java.pdex;
import java.awt.EventQueue;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
@@ -47,12 +51,23 @@ import javax.swing.text.Element;
import javax.swing.text.PlainDocument;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.Compiler;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import processing.app.Library;
import processing.app.Messages;
@@ -97,12 +112,12 @@ public class ErrorCheckerService {
/**
* URLs of extra imports jar files stored here.
*/
protected URL[] classPath;
protected URL[] classPath = {};
/**
* Stores all Problems in the sketch
* Class loader used by compiler check and ASTGenerator, based on classPath
*/
//public List<Problem> problemsList;
protected URLClassLoader classLoader = new URLClassLoader(classPath);
/**
* How many lines are present till the initial class declaration? In static
@@ -123,12 +138,6 @@ public class ErrorCheckerService {
*/
protected boolean loadCompClass = true;
/**
* Compilation Checker object.
*/
protected CompilationChecker compilationChecker;
/**
* List of jar files to be present in compilation checker's classpath
*/
@@ -156,6 +165,11 @@ public class ErrorCheckerService {
*/
protected final XQPreprocessor xqpreproc;
/**
* ASTGenerator for operations on AST
*/
protected final ASTGenerator astGenerator;
/**
* Regexp for import statements. (Used from Processing source)
*/
@@ -171,10 +185,11 @@ public class ErrorCheckerService {
/**
* Error checking doesn't happen before this interval has ellapsed since the
* last runManualErrorCheck() call.
* last request() call.
*/
private final static long errorCheckInterval = 650;
protected volatile CodeCheckResult lastCodeCheckResult = new CodeCheckResult();
private Thread errorCheckerThread;
private final BlockingQueue<Boolean> requestQueue = new ArrayBlockingQueue<>(1);
@@ -261,11 +276,8 @@ public class ErrorCheckerService {
synchronized (astGenerator) {
astGenerator.disposeAllWindows();
}
compilationChecker = null;
classLoader = null;
System.gc();
Messages.loge("Thread stopped: " + editor.getSketch().getName());
System.gc();
running = false;
}
@@ -278,6 +290,7 @@ public class ErrorCheckerService {
errorCheckerThread.start();
}
public void stop() {
cancel();
running = false;
@@ -324,8 +337,6 @@ public class ErrorCheckerService {
}
protected final ASTGenerator astGenerator;
public ASTGenerator getASTGenerator() {
return astGenerator;
}
@@ -356,7 +367,6 @@ public class ErrorCheckerService {
CompilationUnit compilationUnit;
String sourceCode;
int sourceCodeOffset;
final List<Problem> problems = new ArrayList();
@@ -367,12 +377,11 @@ public class ErrorCheckerService {
CodeCheckResult result = new CodeCheckResult();
result.sourceCode = preprocessCode();
result.sourceCodeOffset = 0;
char[] sourceCodeArray = result.sourceCode.toCharArray();
IProblem[] problems;
List<IProblem> problems;
{{ // SYNTAX CHECK
@@ -381,20 +390,15 @@ public class ErrorCheckerService {
parser.setSource(sourceCodeArray);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
Map<String, String> options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, options);
options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8);
options.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED);
parser.setCompilerOptions(options);
parser.setCompilerOptions(COMPILER_OPTIONS);
parser.setStatementsRecovery(true);
result.compilationUnit = (CompilationUnit) parser.createAST(null);
// Store errors returned by the ast parser
problems = result.compilationUnit.getProblems();
problems = Arrays.asList(result.compilationUnit.getProblems());
if (problems.length == 0) {
if (problems.isEmpty()) {
result.syntaxErrors = false;
result.containsErrors = false;
} else {
@@ -405,7 +409,7 @@ public class ErrorCheckerService {
}}
// No syntax errors, proceed for compilation check, Stage 2.
if (problems.length == 0 && !editor.hasJavaTabs()) {
if (problems.isEmpty() && !editor.hasJavaTabs()) {
String sourceCode = xqpreproc.handle(result.sourceCode, programImports);
prepareCompilerClasspath();
@@ -413,17 +417,11 @@ public class ErrorCheckerService {
parser.setSource(sourceCodeArray);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
Map<String, String> options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, options);
options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8);
options.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED);
parser.setCompilerOptions(options);
parser.setCompilerOptions(COMPILER_OPTIONS);
parser.setStatementsRecovery(true);
result.compilationUnit = (CompilationUnit) parser.createAST(null);
result.sourceCode = sourceCode;
result.sourceCodeOffset = 1;
// Currently (Sept, 2012) I'm using Java's reflection api to load the
// CompilationChecker class(from CompilationChecker.jar) that houses the
@@ -441,26 +439,12 @@ public class ErrorCheckerService {
if (loadCompClass) {
classPath = new URL[classpathJars.size()];
classPath = classpathJars.toArray(classPath);
compilationChecker = null;
classLoader = null;
System.gc();
// log("CP Len -- " + classpath.length);
classLoader = new URLClassLoader(classPath);
compilationChecker = new CompilationChecker();
loadCompClass = false;
}
// for(URL cpUrl: classPath) {
// Messages.log("CP jar: " + cpUrl.getPath());
// }
if (compilerSettings == null) {
prepareCompilerSetting();
}
problems = compilationChecker.getErrors(className, sourceCode,
compilerSettings, classLoader);
problems = compileAndReturnProblems(className, sourceCode,
COMPILER_OPTIONS, classLoader);
} catch (Exception e) {
System.err.println("compileCheck() problem." + e);
e.printStackTrace();
@@ -484,7 +468,7 @@ public class ErrorCheckerService {
continue;
}
int sourceLine = problem.getSourceLineNumber() - result.sourceCodeOffset;
int sourceLine = problem.getSourceLineNumber();
int[] a = calculateTabIndexAndLineNumber(sourceLine);
Problem p = new Problem(problem, a[0], a[1]);
@@ -504,8 +488,6 @@ public class ErrorCheckerService {
return result;
}
protected volatile CodeCheckResult lastCodeCheckResult = new CodeCheckResult();
public boolean hasSyntaxErrors(){
return lastCodeCheckResult.syntaxErrors;
}
@@ -514,9 +496,49 @@ public class ErrorCheckerService {
return lastCodeCheckResult.containsErrors;
}
public TreeMap<String, IProblem> tempErrorLog = new TreeMap<>();
/**
* Performs compiler error check.
* @param sourceName - name of the class
* @param source - source code
* @param options - compiler options
* @param classLoader - custom classloader which can load all dependencies
* @return list of compiler errors and warnings
*/
static public List<IProblem> compileAndReturnProblems(String sourceName,
String source,
Map<String, String> options,
URLClassLoader classLoader) {
final List<IProblem> problems = new ArrayList<>();
protected URLClassLoader classLoader;
ICompilerRequestor requestor = new ICompilerRequestor() {
@Override
public void acceptResult(CompilationResult cr) {
if (cr.hasProblems()) Collections.addAll(problems, cr.getProblems());
}
};
final char[] contents = source.toCharArray();
final char[][] packageName = new char[][]{};
final char[] mainTypeName = sourceName.toCharArray();
final char[] fileName = (sourceName + ".java").toCharArray();
ICompilationUnit unit = new ICompilationUnit() {
@Override public char[] getContents() { return contents; }
@Override public char[][] getPackageName() { return packageName; }
@Override public char[] getMainTypeName() { return mainTypeName; }
@Override public char[] getFileName() { return fileName; }
@Override public boolean ignoreOptionalProblems() { return false; }
};
org.eclipse.jdt.internal.compiler.Compiler compiler =
new Compiler(new NameEnvironmentImpl(classLoader),
DefaultErrorHandlingPolicies.proceedWithAllProblems(),
new CompilerOptions(options),
requestor,
new DefaultProblemFactory(Locale.getDefault()));
compiler.compile(new ICompilationUnit[]{unit});
return problems;
}
/**
@@ -538,22 +560,11 @@ public class ErrorCheckerService {
}
pdeTabs.add(tab);
}
int pkgNameOffset = ("package " + className + ";\n").length();
// package name is added only during compile check
if (codeCheckResult.sourceCodeOffset == 0) {
pkgNameOffset = 0;
}
for (Problem p : codeCheckResult.problems) {
int prbStart = p.getIProblem().getSourceStart() - pkgNameOffset;
int prbEnd = p.getIProblem().getSourceEnd() - pkgNameOffset;
int prbStart = p.getIProblem().getSourceStart();
int prbEnd = p.getIProblem().getSourceEnd();
int javaLineNumber = p.getSourceLineNumber() - 1;
// not sure if this is necessary [fry 150808]
javaLineNumber -= codeCheckResult.sourceCodeOffset;
// errors on the first line were setting this to -1 [fry 150808]
if (javaLineNumber < 0) {
javaLineNumber = 0;
}
Element lineElement =
javaSource.getDefaultRootElement().getElement(javaLineNumber);
if (lineElement == null) {
@@ -597,16 +608,7 @@ public class ErrorCheckerService {
}
private int loadClassCounter = 0;
public URLClassLoader getSketchClassLoader() {
loadClassCounter++;
if (loadClassCounter > 100) {
loadClassCounter = 0;
classLoader = null;
System.gc();
classLoader = new URLClassLoader(classPath);
}
return classLoader;
}
@@ -785,29 +787,45 @@ public class ErrorCheckerService {
return true;
}
static final Map<String, String> COMPILER_OPTIONS;
static {
Map<String, String> compilerOptions = new HashMap<>();
/** Options for the JDT Compiler */
protected Map<String, String> compilerSettings;
JavaCore.setComplianceOptions(JavaCore.VERSION_1_7, compilerOptions);
// See http://help.eclipse.org/mars/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Fguide%2Fjdt_api_options.htm&anchor=compiler
/** Set compiler options for JDT Compiler */
protected void prepareCompilerSetting() {
compilerSettings = new HashMap<>();
final String[] generate = {
JavaCore.COMPILER_LINE_NUMBER_ATTR,
JavaCore.COMPILER_SOURCE_FILE_ATTR
};
compilerSettings.put(CompilerOptions.OPTION_LineNumberAttribute,
CompilerOptions.GENERATE);
compilerSettings.put(CompilerOptions.OPTION_SourceFileAttribute,
CompilerOptions.GENERATE);
compilerSettings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_8);
compilerSettings.put(CompilerOptions.OPTION_ReportUnusedImport,
CompilerOptions.IGNORE);
compilerSettings.put(CompilerOptions.OPTION_ReportMissingSerialVersion,
CompilerOptions.IGNORE);
compilerSettings.put(CompilerOptions.OPTION_ReportRawTypeReference,
CompilerOptions.IGNORE);
compilerSettings.put(CompilerOptions.OPTION_ReportUncheckedTypeOperation,
CompilerOptions.IGNORE);
final String[] ignore = {
JavaCore.COMPILER_PB_UNUSED_IMPORT,
JavaCore.COMPILER_PB_MISSING_SERIAL_VERSION,
JavaCore.COMPILER_PB_RAW_TYPE_REFERENCE,
JavaCore.COMPILER_PB_REDUNDANT_TYPE_ARGUMENTS,
JavaCore.COMPILER_PB_UNCHECKED_TYPE_OPERATION
};
final String[] warn = {
JavaCore.COMPILER_PB_NO_EFFECT_ASSIGNMENT,
JavaCore.COMPILER_PB_NULL_REFERENCE,
JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE,
JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK,
JavaCore.COMPILER_PB_POSSIBLE_ACCIDENTAL_BOOLEAN_ASSIGNMENT,
JavaCore.COMPILER_PB_UNUSED_LABEL,
JavaCore.COMPILER_PB_UNUSED_LOCAL,
JavaCore.COMPILER_PB_UNUSED_OBJECT_ALLOCATION,
JavaCore.COMPILER_PB_UNUSED_PARAMETER,
JavaCore.COMPILER_PB_UNUSED_PRIVATE_MEMBER
};
for (String s : generate) compilerOptions.put(s, JavaCore.GENERATE);
for (String s : ignore) compilerOptions.put(s, JavaCore.IGNORE);
for (String s : warn) compilerOptions.put(s, JavaCore.WARNING);
COMPILER_OPTIONS = Collections.unmodifiableMap(compilerOptions);
}
@@ -1499,4 +1517,74 @@ public class ErrorCheckerService {
public ArrayList<ImportStatement> getProgramImports() {
return programImports;
}
private static class NameEnvironmentImpl implements INameEnvironment {
private final ClassLoader classLoader;
NameEnvironmentImpl(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
return readClassFile(CharOperation.toString(compoundTypeName), classLoader);
}
@Override
public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
String fullName = CharOperation.toString(packageName);
if (typeName != null) {
if (fullName.length() > 0) fullName += ".";
fullName += new String(typeName);
}
return readClassFile(fullName, classLoader);
}
@Override
public boolean isPackage(char[][] parentPackageName, char[] packageName) {
String fullName = CharOperation.toString(parentPackageName);
if (packageName != null) {
if (fullName.length() > 0) fullName += ".";
fullName += new String(packageName);
}
if (readClassFile(fullName, classLoader) != null) return false;
try {
return (classLoader.loadClass(fullName) == null);
} catch (ClassNotFoundException e) {
return true;
}
}
@Override
public void cleanup() { }
private static NameEnvironmentAnswer readClassFile(String fullName, ClassLoader classLoader) {
String classFileName = fullName.replace('.', '/') + ".class";
InputStream is = classLoader.getResourceAsStream(classFileName);
if (is == null) return null;
byte[] buffer = new byte[8192];
ByteArrayOutputStream os = new ByteArrayOutputStream(buffer.length);
try {
int bytes;
while ((bytes = is.read(buffer, 0, buffer.length)) > 0) {
os.write(buffer, 0, bytes);
}
os.flush();
ClassFileReader classFileReader =
new ClassFileReader(os.toByteArray(), fullName.toCharArray(), true);
return new NameEnvironmentAnswer(classFileReader, null);
} catch (IOException | ClassFormatException e) {
return null;
}
}
}
}
@@ -21,9 +21,7 @@
package processing.mode.java.pdex;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
@@ -76,12 +74,7 @@ public class XQPreprocessor {
parser.setSource(doc.get().toCharArray());
parser.setKind(ASTParser.K_COMPILATION_UNIT);
@SuppressWarnings("unchecked")
Map<String, String> options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, options);
options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8);
parser.setCompilerOptions(options);
parser.setCompilerOptions(ErrorCheckerService.COMPILER_OPTIONS);
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
cu.recordModifications();
rewrite = ASTRewrite.create(cu.getAST());
@@ -90,9 +83,7 @@ public class XQPreprocessor {
TextEdit edits = cu.rewrite(doc, null);
try {
edits.apply(doc);
} catch (MalformedTreeException e) {
e.printStackTrace();
} catch (BadLocationException e) {
} catch (MalformedTreeException | BadLocationException e) {
e.printStackTrace();
}
return doc.get();