blob: f016ca4459fef01d5617a2ce8f5141da9e125d26 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.core.tests.eval;
import java.io.File;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.tests.runtime.LocalVMLauncher;
import org.eclipse.jdt.core.tests.runtime.LocalVirtualMachine;
import org.eclipse.jdt.core.tests.runtime.TargetException;
import org.eclipse.jdt.core.tests.runtime.TargetInterface;
import org.eclipse.jdt.core.tests.util.Util;
import org.eclipse.jdt.internal.compiler.ClassFile;
import org.eclipse.jdt.internal.compiler.IProblemFactory;
import org.eclipse.jdt.internal.compiler.batch.FileSystem;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.env.IBinaryField;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.eval.EvaluationContext;
import org.eclipse.jdt.internal.eval.EvaluationResult;
import org.eclipse.jdt.internal.eval.GlobalVariable;
import org.eclipse.jdt.internal.eval.IRequestor;
public class SimpleTest {
static final String JRE_PATH = Util.getJREDirectory();
static final String[] COMPILATION_CLASSPATH = new String[] {Util.getJavaClassLib(), Util.getOutputDirectory()};
static final String[] RUNTIME_CLASSPATH = new String[] {Util.getOutputDirectory()};
static final String TARGET_PATH = Util.getOutputDirectory() + File.separator + "evaluation";
protected EvaluationContext context;
protected LocalVirtualMachine launchedVM;
protected TargetInterface target;
protected Requestor requestor;
class Requestor implements IRequestor {
int globalProblemCount = 0;
public boolean acceptClassFiles(ClassFile[] classFiles, char[] codeSnippetClassName) {
try {
target.sendClasses(codeSnippetClassName != null, classFiles);
} catch (TargetException e) {
return false;
}
if (codeSnippetClassName != null) {
TargetInterface.Result result = target.getResult();
if (result.displayString == null) {
System.out.println("(No explicit return value)");
} else {
System.out.print("(");
System.out.print(result.typeName);
System.out.print(") ");
System.out.println(result.displayString);
}
} else {
for (int i = 0, length = classFiles.length; i < length; i++) {
char[][] compoundName = classFiles[i].getCompoundName();
if (new String(compoundName[compoundName.length-1]).startsWith("GlobalVariable")) {
try {
IBinaryField[] fields = new ClassFileReader(classFiles[i].getBytes(), null).getFields();
if (fields != null) {
for (int j = 0; j < fields.length; j++) {
TargetInterface.Result result = target.getResult();
if (result.displayString == null) {
System.out.println("(No explicit return value)");
} else {
System.out.print("(");
System.out.print(result.typeName);
System.out.print(") ");
System.out.println(result.displayString);
}
}
}
} catch (ClassFormatException e) {
}
}
}
}
return true;
}
public void acceptProblem(IProblem problem, char[] fragmentSource, int fragmentKind) {
int localErrorCount = 0;
globalProblemCount++;
char[] source = fragmentSource;
if (localErrorCount == 0)
System.out.println("----------");
if (fragmentKind == EvaluationResult.T_INTERNAL) {
System.out.print(globalProblemCount + (problem.isError() ? ". INTERNAL ERROR" : ". INTERNAL WARNING"));
System.out.print(" in generated compilation unit");
} else {
System.out.print(globalProblemCount + (problem.isError() ? ". ERROR" : ". WARNING"));
System.out.print(" in ");
switch (fragmentKind) {
case EvaluationResult.T_PACKAGE:
System.out.print("package");
break;
case EvaluationResult.T_IMPORT:
System.out.print("import");
break;
case EvaluationResult.T_CODE_SNIPPET:
System.out.print("code snippet");
break;
case EvaluationResult.T_VARIABLE:
int line = problem.getSourceLineNumber();
if (line == -1) {
System.out.print("variable type");
source = findVar(fragmentSource).getTypeName();
} else if (line == 0) {
System.out.print("variable name");
source = findVar(fragmentSource).getName();
} else {
System.out.print("variable initializer");
source = findVar(fragmentSource).getInitializer();
}
break;
}
}
System.out.println(errorReportSource((DefaultProblem)problem, source));
System.out.println(problem.getMessage());
System.out.println("----------");
if (problem.isError())
localErrorCount++;
}
}
/**
* Build a char array from the given lines
*/
protected char[] buildCharArray(String[] lines) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < lines.length; i++) {
buffer.append(lines[i]);
if (i < lines.length -1) {
buffer.append("\n");
}
}
int length = buffer.length();
char[] result = new char[length];
buffer.getChars(0, length, result, 0);
return result;
}
protected String errorReportSource(DefaultProblem problem, char[] source) {
//extra from the source the innacurate token
//and "highlight" it using some underneath ^^^^^
//put some context around too.
//this code assumes that the font used in the console is fixed size
//sanity .....
if ((problem.getSourceStart() > problem.getSourceEnd()) || ((problem.getSourceStart() < 0) && (problem.getSourceEnd() < 0)))
return "\n!! no source information available !!";
//regular behavior....(slow code)
final char SPACE = '\u0020';
final char MARK = '^';
final char TAB = '\t';
//the next code tries to underline the token.....
//it assumes (for a good display) that token source does not
//contain any \r \n. This is false on statements !
//(the code still works but the display is not optimal !)
//compute the how-much-char we are displaying around the inaccurate token
int begin = problem.getSourceStart() >= source.length ? source.length - 1 : problem.getSourceStart();
int relativeStart = 0;
int end = problem.getSourceEnd() >= source.length ? source.length - 1 : problem.getSourceEnd();
int relativeEnd = 0;
label : for (relativeStart = 0;; relativeStart++) {
if (begin == 0)
break label;
if ((source[begin - 1] == '\n') || (source[begin - 1] == '\r'))
break label;
begin--;
}
label : for (relativeEnd = 0;; relativeEnd++) {
if ((end + 1) >= source.length)
break label;
if ((source[end + 1] == '\r') || (source[end + 1] == '\n')) {
break label;
}
end++;
}
//extract the message form the source
char[] extract = new char[end - begin + 1];
System.arraycopy(source, begin, extract, 0, extract.length);
char c;
//remove all SPACE and TAB that begin the error message...
int trimLeftIndex = 0;
while (((c = extract[trimLeftIndex++]) == TAB) || (c == SPACE)) {
};
System.arraycopy(extract, trimLeftIndex - 1, extract = new char[extract.length - trimLeftIndex + 1], 0, extract.length);
relativeStart -= trimLeftIndex;
//buffer spaces and tabs in order to reach the error position
int pos = 0;
char[] underneath = new char[extract.length]; // can't be bigger
for (int i = 0; i <= relativeStart; i++) {
if (extract[i] == TAB) {
underneath[pos++] = TAB;
} else {
underneath[pos++] = SPACE;
}
}
//mark the error position
for (int i = problem.getSourceStart(); i <= (problem.getSourceEnd() >= source.length ? source.length - 1 : problem.getSourceEnd()); i++)
underneath[pos++] = MARK;
//resize underneathto remove 'null' chars
System.arraycopy(underneath, 0, underneath = new char[pos], 0, pos);
return
((problem.getSourceLineNumber() > 0) ?
(" (at line " + String.valueOf(problem.getSourceLineNumber()) + ")") :
""
) +
"\n\t" + new String(extract) + "\n\t" + new String(underneath);
}
protected GlobalVariable findVar(char[] varName) {
GlobalVariable[] vars = this.context.allVariables();
for (int i = 0; i < vars.length; i++) {
GlobalVariable var = vars[i];
if (CharOperation.equals(var.getName(), varName)) {
return var;
}
}
return null;
}
protected INameEnvironment getEnv() {
return new FileSystem(COMPILATION_CLASSPATH, new String[0], null);
}
protected IProblemFactory getProblemFactory() {
return new DefaultProblemFactory(java.util.Locale.getDefault());
}
protected void startEvaluationContext() throws TargetException {
LocalVMLauncher launcher = LocalVMLauncher.getLauncher();
launcher.setVMPath(JRE_PATH);
launcher.setClassPath(RUNTIME_CLASSPATH);
int evalPort = Util.nextAvailablePortNumber();
launcher.setEvalPort(evalPort);
launcher.setEvalTargetPath(TARGET_PATH);
this.launchedVM = launcher.launch();
(new Thread() {
public void run() {
try {
java.io.InputStream in = SimpleTest.this.launchedVM.getInputStream();
int read = 0;
while (read != -1) {
try {
read = in.read();
} catch (java.io.IOException e) {
read = -1;
}
if (read != -1) {
System.out.print((char)read);
}
}
} catch (TargetException e) {
}
}
}).start();
(new Thread() {
public void run() {
try {
java.io.InputStream in = SimpleTest.this.launchedVM.getErrorStream();
int read = 0;
while (read != -1) {
try {
read = in.read();
} catch (java.io.IOException e) {
read = -1;
}
if (read != -1) {
System.out.print((char)read);
}
}
} catch (TargetException e) {
}
}
}).start();
this.requestor = new Requestor();
this.target = new TargetInterface();
this.target.connect("localhost", evalPort, 10000);
this.context = new EvaluationContext();
}
protected void stopEvaluationContext() throws TargetException {
try {
this.target.disconnect(); // Close the socket first so that the OS resource has a chance to be freed.
int retry = 0;
while (this.launchedVM.isRunning() && (++retry < 20)) {
try {
Thread.sleep(retry * 100);
} catch (InterruptedException e) {
}
}
if (this.launchedVM.isRunning()) {
this.launchedVM.shutDown();
}
this.context = null;
} catch (TargetException e) {
throw new Error(e.getMessage());
}
}
}