package org.eclipse.jdt.internal.eval;
import java.util.Locale;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.CompletionRequestor;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.compiler.*;
import org.eclipse.jdt.internal.codeassist.CompletionEngine;
import org.eclipse.jdt.internal.codeassist.ISelectionRequestor;
import org.eclipse.jdt.internal.codeassist.SelectionEngine;
import org.eclipse.jdt.internal.compiler.ClassFile;
import org.eclipse.jdt.internal.compiler.IProblemFactory;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.internal.core.SearchableEnvironment;
import org.eclipse.jdt.internal.core.util.Util;
public class EvaluationContext implements EvaluationConstants, SuffixConstants {
static int VAR_CLASS_COUNTER = 0;
static int CODE_SNIPPET_COUNTER = 0;
GlobalVariable[] variables;
int variableCount;
char[][] imports;
char[] packageName;
boolean varsChanged;
VariablesInfo installedVars;
IBinaryType codeSnippetBinary;
String lineSeparator;
char[] declaringTypeName;
int[] localVariableModifiers;
char[][] localVariableTypeNames;
char[][] localVariableNames;
boolean isStatic;
boolean isConstructorCall;
public EvaluationContext() {
this.variables = new GlobalVariable[5];
this.variableCount = 0;
this.imports = CharOperation.NO_CHAR_CHAR;
this.packageName = CharOperation.NO_CHAR;
this.varsChanged = true;
this.isStatic = true;
this.isConstructorCall = false;
this.lineSeparator = org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR;
}
public GlobalVariable[] allVariables() {
GlobalVariable[] result = new GlobalVariable[this.variableCount];
System.arraycopy(this.variables, 0, result, 0, this.variableCount);
return result;
}
public void complete(
char[] codeSnippet,
int completionPosition,
SearchableEnvironment environment,
CompletionRequestor requestor,
Map<String, String> options,
final IJavaProject project,
WorkingCopyOwner owner,
IProgressMonitor monitor) {
try {
IRequestor variableRequestor = new IRequestor() {
@Override
public boolean acceptClassFiles(ClassFile[] classFiles, char[] codeSnippetClassName) {
return true;
}
@Override
public void acceptProblem(CategorizedProblem problem, char[] fragmentSource, int fragmentKind) {
}
};
evaluateVariables(environment, options, variableRequestor, new DefaultProblemFactory(Locale.getDefault()));
} catch (InstallException e) {
}
final char[] className = "CodeSnippetCompletion".toCharArray();
final long complianceVersion = CompilerOptions.versionToJdkLevel(options.get(JavaCore.COMPILER_COMPLIANCE));
final CodeSnippetToCuMapper mapper = new CodeSnippetToCuMapper(
codeSnippet,
this.packageName,
this.imports,
className,
this.installedVars == null ? null : this.installedVars.className,
this.localVariableNames,
this.localVariableTypeNames,
this.localVariableModifiers,
this.declaringTypeName,
this.lineSeparator,
complianceVersion
);
ICompilationUnit sourceUnit = new ICompilationUnit() {
@Override
public char[] getFileName() {
return CharOperation.concat(className, Util.defaultJavaExtension().toCharArray());
}
@Override
public char[] getContents() {
return mapper.getCUSource(EvaluationContext.this.lineSeparator);
}
@Override
public char[] getMainTypeName() {
return className;
}
@Override
public char[][] getPackageName() {
return null;
}
@Override
public boolean ignoreOptionalProblems() {
return false;
}
@Override
public char[] getModuleName() {
return null;
}
};
CompletionEngine engine = new CompletionEngine(environment, mapper.getCompletionRequestor(requestor), options, project, owner, monitor);
if (this.installedVars != null) {
IBinaryType binaryType = getRootCodeSnippetBinary();
if (binaryType != null) {
engine.lookupEnvironment.cacheBinaryType(binaryType, null );
}
ClassFile[] classFiles = this.installedVars.classFiles;
for (int i = 0; i < classFiles.length; i++) {
ClassFile classFile = classFiles[i];
IBinaryType binary = null;
try {
binary = new ClassFileReader(classFile.getBytes(), null);
} catch (ClassFormatException e) {
e.printStackTrace();
}
engine.lookupEnvironment.cacheBinaryType(binary, null );
}
}
engine.complete(sourceUnit, mapper.startPosOffset + completionPosition, mapper.startPosOffset, null);
}
public void deleteVariable(GlobalVariable variable) {
GlobalVariable[] vars = this.variables;
int index = -1;
for (int i = 0; i < this.variableCount; i++) {
if (vars[i].equals(variable)) {
index = i;
break;
}
}
if (index == -1) {
return;
}
int elementCount = this.variableCount--;
int j = elementCount - index - 1;
if (j > 0) {
System.arraycopy(vars, index + 1, vars, index, j);
}
vars[elementCount - 1] = null;
this.varsChanged = true;
}
private void deployCodeSnippetClassIfNeeded(IRequestor requestor) throws InstallException {
if (this.codeSnippetBinary == null) {
if (!requestor.acceptClassFiles(
new ClassFile[] {
new ClassFile() {
@Override
public byte[] getBytes() {
return getCodeSnippetBytes();
}
@Override
public char[][] getCompoundName() {
return EvaluationConstants.ROOT_COMPOUND_NAME;
}
}
},
null))
throw new InstallException();
}
}
public void evaluate(
char[] codeSnippet,
char[][] contextLocalVariableTypeNames,
char[][] contextLocalVariableNames,
int[] contextLocalVariableModifiers,
char[] contextDeclaringTypeName,
boolean contextIsStatic,
boolean contextIsConstructorCall,
INameEnvironment environment,
Map<String, String> options,
final IRequestor requestor,
IProblemFactory problemFactory) throws InstallException {
this.localVariableTypeNames = contextLocalVariableTypeNames;
this.localVariableNames = contextLocalVariableNames;
this.localVariableModifiers = contextLocalVariableModifiers;
this.declaringTypeName = contextDeclaringTypeName;
this.isStatic = contextIsStatic;
this.isConstructorCall = contextIsConstructorCall;
deployCodeSnippetClassIfNeeded(requestor);
try {
class ForwardingRequestor implements IRequestor {
boolean hasErrors = false;
@Override
public boolean acceptClassFiles(ClassFile[] classFiles, char[] codeSnippetClassName) {
return requestor.acceptClassFiles(classFiles, codeSnippetClassName);
}
@Override
public void acceptProblem(CategorizedProblem problem, char[] fragmentSource, int fragmentKind) {
requestor.acceptProblem(problem, fragmentSource, fragmentKind);
if (problem.isError()) {
this.hasErrors = true;
}
}
}
ForwardingRequestor forwardingRequestor = new ForwardingRequestor();
if (this.varsChanged) {
evaluateVariables(environment, options, forwardingRequestor, problemFactory);
}
if (!forwardingRequestor.hasErrors) {
Evaluator evaluator =
new CodeSnippetEvaluator(
codeSnippet,
this,
environment,
options,
requestor,
problemFactory);
ClassFile[] classes = evaluator.getClasses();
if (classes != null && classes.length > 0) {
char[] simpleClassName = evaluator.getClassName();
char[] pkgName = getPackageName();
char[] qualifiedClassName =
pkgName.length == 0 ?
simpleClassName :
CharOperation.concat(pkgName, simpleClassName, '.');
CODE_SNIPPET_COUNTER++;
if (!requestor.acceptClassFiles(classes, qualifiedClassName))
throw new InstallException();
}
}
} finally {
this.localVariableTypeNames = null;
this.localVariableNames = null;
this.localVariableModifiers = null;
this.declaringTypeName = null;
this.isStatic = true;
this.isConstructorCall = false;
}
}
public void evaluate(char[] codeSnippet, INameEnvironment environment, Map<String, String> options, final IRequestor requestor, IProblemFactory problemFactory) throws InstallException {
this.evaluate(
codeSnippet,
null,
null,
null,
null,
true,
false,
environment,
options,
requestor,
problemFactory);
}
public void evaluateImports(INameEnvironment environment, IRequestor requestor, IProblemFactory problemFactory) {
for (int i = 0; i < this.imports.length; i++) {
CategorizedProblem[] problems = new CategorizedProblem[] {null};
char[] importDeclaration = this.imports[i];
char[][] splitDeclaration = CharOperation.splitOn('.', importDeclaration);
int splitLength = splitDeclaration.length;
if (splitLength > 0) {
char[] pkgName = splitDeclaration[splitLength - 1];
if (pkgName.length == 1 && pkgName[0] == '*') {
char[][] parentName;
switch (splitLength) {
case 1:
parentName = null;
break;
case 2:
parentName = null;
pkgName = splitDeclaration[splitLength - 2];
break;
default:
parentName = CharOperation.subarray(splitDeclaration, 0, splitLength - 2);
pkgName = splitDeclaration[splitLength - 2];
}
if (!environment.isPackage(parentName, pkgName)) {
String[] arguments = new String[] {new String(importDeclaration)};
problems[0] = problemFactory.createProblem(importDeclaration, IProblem.ImportNotFound, arguments, arguments, ProblemSeverities.Warning, 0, importDeclaration.length - 1, i, 0);
}
} else {
if (environment.findType(splitDeclaration) == null) {
String[] arguments = new String[] {new String(importDeclaration)};
problems[0] = problemFactory.createProblem(importDeclaration, IProblem.ImportNotFound, arguments, arguments, ProblemSeverities.Warning, 0, importDeclaration.length - 1, i, 0);
}
}
} else {
String[] arguments = new String[] {new String(importDeclaration)};
problems[0] = problemFactory.createProblem(importDeclaration, IProblem.ImportNotFound, arguments, arguments, ProblemSeverities.Warning, 0, importDeclaration.length - 1, i, 0);
}
if (problems[0] != null) {
requestor.acceptProblem(problems[0], importDeclaration, EvaluationResult.T_IMPORT);
}
}
}
public void evaluateVariable(GlobalVariable variable, INameEnvironment environment, Map<String, String> options, IRequestor requestor, IProblemFactory problemFactory) throws InstallException {
this.evaluate(variable.getName(), environment, options, requestor, problemFactory);
}
public void evaluateVariables(INameEnvironment environment, Map<String, String> options, IRequestor requestor, IProblemFactory problemFactory) throws InstallException {
deployCodeSnippetClassIfNeeded(requestor);
VariablesEvaluator evaluator = new VariablesEvaluator(this, environment, options, requestor, problemFactory);
ClassFile[] classes = evaluator.getClasses();
if (classes != null) {
if (classes.length > 0) {
Util.sort(classes, new Util.Comparer() {
@Override
public int compare(Object a, Object b) {
if (a == b) return 0;
ClassFile enclosing = ((ClassFile) a).enclosingClassFile;
while (enclosing != null) {
if (enclosing == b)
return 1;
enclosing = enclosing.enclosingClassFile;
}
return -1;
}
});
if (!requestor.acceptClassFiles(classes, null)) {
throw new InstallException();
}
int count = this.variableCount;
GlobalVariable[] variablesCopy = new GlobalVariable[count];
System.arraycopy(this.variables, 0, variablesCopy, 0, count);
this.installedVars = new VariablesInfo(evaluator.getPackageName(), evaluator.getClassName(), classes, variablesCopy, count);
VAR_CLASS_COUNTER++;
}
this.varsChanged = false;
}
}
byte[] getCodeSnippetBytes() {
return new byte[] {
-54, -2, -70, -66, 0, 3, 0, 45, 0, 35, 1, 0, 48, 111, 114, 103, 47, 101, 99, 108, 105, 112, 115, 101, 47, 106, 100, 116, 47, 105, 110, 116, 101, 114, 110, 97, 108, 47, 101, 118, 97, 108, 47, 116, 97, 114, 103, 101, 116, 47, 67, 111, 100, 101, 83, 110, 105, 112, 112, 101, 116, 7, 0, 1, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 7, 0, 3, 1, 0, 10, 114, 101, 115, 117, 108, 116, 84, 121, 112, 101, 1, 0, 17, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 67, 108, 97, 115, 115, 59, 1, 0, 11, 114, 101, 115, 117, 108, 116, 86, 97, 108, 117, 101, 1, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 59, 1, 0, 7, 99, 108, 97, 115, 115, 36, 48, 1, 0, 9, 83, 121, 110, 116, 104, 101, 116, 105, 99, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 12, 0, 11, 0, 12, 10, 0, 4, 0, 14, 1, 0, 14, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 86, 111, 105, 100, 7, 0, 16, 1, 0, 4, 84, 89, 80, 69, 12, 0, 18, 0, 6, 9, 0, 17, 0, 19, 12, 0, 5, 0, 6, 9, 0, 2, 0, 21, 12, 0, 7, 0, 8, 9, 0, 2, 0, 23, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 13, 103, 101, 116, 82, 101, 115, 117, 108, 116, 84, 121, 112, 101, 1, 0, 19, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 67, 108, 97, 115, 115, 59, 1, 0, 14, 103, 101, 116, 82, 101, 115, 117, 108, 116, 86, 97, 108, 117, 101, 1, 0, 20, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 59, 1, 0, 3, 114, 117, 110, 1, 0, 9, 115, 101, 116, 82, 101, 115, 117, 108, 116, 1, 0, 38, 40, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 59, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 67, 108, 97, 115, 115, 59, 41, 86, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 16, 67, 111, 100, 101, 83, 110, 105, 112, 112, 101, 116, 46, 106, 97, 118, 97, 0, 33, 0, 2, 0, 4, 0, 0, 0, 3, 0, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 7, 0, 8, 0, 0, 0, 8, 0, 9, 0, 6, 0, 1, 0, 10, 0, 0, 0, 0, 0, 5, 0, 1, 0, 11, 0, 12, 0, 1, 0, 13, 0, 0, 0, 53, 0, 2, 0, 1, 0, 0, 0, 17, 42, -73, 0, 15, 42, -78, 0, 20, -75, 0, 22, 42, 1, -75, 0, 24, -79, 0, 0, 0, 1, 0, 25, 0, 0, 0, 18, 0, 4, 0, 0, 0, 17, 0, 4, 0, 18, 0, 11, 0, 19, 0, 16, 0, 17, 0, 1, 0, 26, 0, 27, 0, 1, 0, 13, 0, 0, 0, 29, 0, 1, 0, 1, 0, 0, 0, 5, 42, -76, 0, 22, -80, 0, 0, 0, 1, 0, 25, 0, 0, 0, 6, 0, 1, 0, 0, 0, 24, 0, 1, 0, 28, 0, 29, 0, 1, 0, 13, 0, 0, 0, 29, 0, 1, 0, 1, 0, 0, 0, 5, 42, -76, 0, 24, -80, 0, 0, 0, 1, 0, 25, 0, 0, 0, 6, 0, 1, 0, 0, 0, 30, 0, 1, 0, 30, 0, 12, 0, 1, 0, 13, 0, 0, 0, 25, 0, 0, 0, 1, 0, 0, 0, 1, -79, 0, 0, 0, 1, 0, 25, 0, 0, 0, 6, 0, 1, 0, 0, 0, 36, 0, 1, 0, 31, 0, 32, 0, 1, 0, 13, 0, 0, 0, 43, 0, 2, 0, 3, 0, 0, 0, 11, 42, 43, -75, 0, 24, 42, 44, -75, 0, 22, -79, 0, 0, 0, 1, 0, 25, 0, 0, 0, 14, 0, 3, 0, 0, 0, 42, 0, 5, 0, 43, 0, 10, 0, 41, 0, 1, 0, 33, 0, 0, 0, 2, 0, 34
};
}
public static String getCodeSnippetSource() {
return
"package org.eclipse.jdt.internal.eval.target;\n" +
"\n" +
"/*\n" +
" * (c) Copyright IBM Corp. 2000, 2001.\n" +
" * All Rights Reserved.\n" +
" */\n" +
"/**\n" +
" * The root of all code snippet classes. Code snippet classes\n" +
" * are supposed to overide the run() method.\n" +
" * <p>\n" +
" * IMPORTANT NOTE:\n" +
" * All methods in this class must be public since this class is going to be loaded by the\n" +
" * bootstrap class loader, and the other code snippet support classes might be loaded by \n" +
" * another class loader (so their runtime packages are going to be different).\n" +
" */\n" +
"public class CodeSnippet {\n" +
" private Class resultType = void.class;\n" +
" private Object resultValue = null;\n" +
"/**\n" +
" * Returns the result type of the code snippet evaluation.\n" +
" */\n" +
"public Class getResultType() {\n" +
" return this.resultType;\n" +
"}\n" +
"/**\n" +
" * Returns the result value of the code snippet evaluation.\n" +
" */\n" +
"public Object getResultValue() {\n" +
" return this.resultValue;\n" +
"}\n" +
"/**\n" +
" * The code snippet. Subclasses must override this method with a transformed code snippet\n" +
" * that stores the result using setResult(Class, Object).\n" +
" */\n" +
"public void run() {\n" +
"}\n" +
"/**\n" +
" * Stores the result type and value of the code snippet evaluation.\n" +
" */\n" +
"public void setResult(Object someResultValue, Class someResultType) {\n" +
" this.resultValue = someResultValue;\n" +
" this.resultType = someResultType;\n" +
"}\n" +
"}\n";
}
public char[][] getImports() {
return this.imports;
}
public char[] getPackageName() {
return this.packageName;
}
IBinaryType getRootCodeSnippetBinary() {
if (this.codeSnippetBinary == null) {
this.codeSnippetBinary = new CodeSnippetSkeleton();
}
return this.codeSnippetBinary;
}
public char[] getVarClassName() {
if (this.installedVars == null) return CharOperation.NO_CHAR;
return CharOperation.concat(this.installedVars.packageName, this.installedVars.className, '.');
}
public GlobalVariable newVariable(char[] typeName, char[] name, char[] initializer) {
GlobalVariable var = new GlobalVariable(typeName, name, initializer);
if (this.variableCount >= this.variables.length)
System.arraycopy(this.variables, 0, this.variables = new GlobalVariable[this.variableCount * 2], 0, this.variableCount);
this.variables[this.variableCount++] = var;
this.varsChanged = true;
return var;
}
public void select(
char[] codeSnippet,
int selectionSourceStart,
int selectionSourceEnd,
SearchableEnvironment environment,
ISelectionRequestor requestor,
Map<String, String> options,
WorkingCopyOwner owner) {
final char[] className = "CodeSnippetSelection".toCharArray();
final long complianceVersion = CompilerOptions.versionToJdkLevel(options.get(JavaCore.COMPILER_COMPLIANCE));
final CodeSnippetToCuMapper mapper = new CodeSnippetToCuMapper(
codeSnippet,
this.packageName,
this.imports,
className,
this.installedVars == null ? null : this.installedVars.className,
this.localVariableNames,
this.localVariableTypeNames,
this.localVariableModifiers,
this.declaringTypeName,
this.lineSeparator,
complianceVersion
);
ICompilationUnit sourceUnit = new ICompilationUnit() {
@Override
public char[] getFileName() {
return CharOperation.concat(className, Util.defaultJavaExtension().toCharArray());
}
@Override
public char[] getContents() {
return mapper.getCUSource(EvaluationContext.this.lineSeparator);
}
@Override
public char[] getMainTypeName() {
return className;
}
@Override
public char[][] getPackageName() {
return null;
}
@Override
public boolean ignoreOptionalProblems() {
return false;
}
@Override
public char[] getModuleName() {
return null;
}
};
SelectionEngine engine = new SelectionEngine(environment, mapper.getSelectionRequestor(requestor), options, owner);
engine.select(sourceUnit, mapper.startPosOffset + selectionSourceStart, mapper.startPosOffset + selectionSourceEnd);
}
public void setImports(char[][] imports) {
this.imports = imports;
this.varsChanged = true;
}
public void setLineSeparator(String lineSeparator) {
this.lineSeparator = lineSeparator;
}
public void setPackageName(char[] packageName) {
this.packageName = packageName;
this.varsChanged = true;
}
}