blob: fd96616f4e1b7edd49d4dd29f47642c4aa0e9df4 [file] [log] [blame]
package org.eclipse.jdt.internal.eval;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.jdt.internal.codeassist.*;
import org.eclipse.jdt.internal.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.env.IConstants;
import org.eclipse.jdt.internal.compiler.util.CharOperation;
import org.eclipse.jdt.internal.core.JavaModelManager;
/**
* Maps back and forth a code snippet to a compilation unit.
* The structure of the compilation unit is as follows:
* [package <package name>;]
* [import <import name>;]*
* public class <code snippet class name> extends <global variable class name> {
* public void run() {
* <code snippet>
* }
* }
*/
class CodeSnippetToCuMapper implements EvaluationConstants {
/**
* The generated compilation unit.
*/
public char[] cuSource;
/**
* Where the code snippet starts in the generated compilation unit.
*/
public int lineNumberOffset = 0;
public int startPosOffset = 0;
// Internal fields
private char[] codeSnippet;
private char[] packageName;
private char[][] imports;
char[] className; // NB: Make it package default visibility to optimize access from inner classes
private char[] varClassName;
// Mapping of external local variables
private char[][] localVarNames;
private char[][] localVarTypeNames;
private int[] localVarModifiers;
private char[] declaringTypeName;
/**
* Rebuild source in presence of external local variables
*/
public CodeSnippetToCuMapper(char[] codeSnippet, char[] packageName, char[][] imports, char[] className, char[] varClassName, char[][] localVarNames, char[][] localVarTypeNames, int[] localVarModifiers, char[] declaringTypeName) {
this.codeSnippet = codeSnippet;
this.packageName = packageName;
this.imports = imports;
this.className = className;
this.varClassName = varClassName;
this.localVarNames = localVarNames;
this.localVarTypeNames = localVarTypeNames;
this.localVarModifiers = localVarModifiers;
this.declaringTypeName = declaringTypeName;
this.buildCUSource();
}
private void buildCUSource() {
StringBuffer buffer = new StringBuffer();
// package declaration
if (this.packageName != null && this.packageName.length != 0) {
buffer.append("package "/*nonNLS*/);
buffer.append(this.packageName);
buffer.append(";"/*nonNLS*/).append(JavaModelManager.LINE_SEPARATOR);
this.lineNumberOffset++;
}
// import declarations
char[][] imports = this.imports;
for (int i = 0; i < imports.length; i++) {
buffer.append("import "/*nonNLS*/);
buffer.append(imports[i]);
buffer.append(';').append(JavaModelManager.LINE_SEPARATOR);
this.lineNumberOffset++;
}
// class declaration
buffer.append("public class "/*nonNLS*/);
buffer.append(this.className);
// super class is either a global variable class or the CodeSnippet class
if (this.varClassName != null) {
buffer.append(" extends "/*nonNLS*/);
buffer.append(this.varClassName);
} else {
buffer.append(" extends "/*nonNLS*/);
buffer.append(PACKAGE_NAME);
buffer.append("."/*nonNLS*/);
buffer.append(ROOT_CLASS_NAME);
}
buffer.append(" {"/*nonNLS*/).append(JavaModelManager.LINE_SEPARATOR);
this.lineNumberOffset++;
if (this.declaringTypeName != null){
buffer.append(" "/*nonNLS*/);
buffer.append(this.declaringTypeName);
buffer.append(" "/*nonNLS*/);
buffer.append(DELEGATE_THIS); // val$this
buffer.append(';').append(JavaModelManager.LINE_SEPARATOR);
this.lineNumberOffset++;
}
// add some storage location for local variable persisted state
if (localVarNames != null) {
for (int i = 0, max = localVarNames.length; i < max; i++) {
buffer.append(" "/*nonNLS*/);
buffer.append(localVarTypeNames[i]);
buffer.append(" "/*nonNLS*/);
buffer.append(LOCAL_VAR_PREFIX); // val$...
buffer.append(localVarNames[i]);
buffer.append(';').append(JavaModelManager.LINE_SEPARATOR);
this.lineNumberOffset++;
}
}
// run() method declaration
buffer.append("public void run() throws Throwable {"/*nonNLS*/).append(JavaModelManager.LINE_SEPARATOR);
this.lineNumberOffset++;
startPosOffset = buffer.length();
buffer.append(codeSnippet);
buffer.append('}').append(JavaModelManager.LINE_SEPARATOR);
// end of class declaration
buffer.append('}').append(JavaModelManager.LINE_SEPARATOR);
// store result
int length = buffer.length();
this.cuSource = new char[length];
buffer.getChars(0, length, this.cuSource, 0);
}
/**
* Returns a completion requestor that wraps the given requestor and shift the results
* according to the start offset and line number offset of the code snippet in the generated compilation unit.
*/
public ICompletionRequestor getCompletionRequestor(final ICompletionRequestor originalRequestor) {
final int startPosOffset = this.startPosOffset;
final int lineNumberOffset = this.lineNumberOffset;
return new ICompletionRequestor() {
public void acceptClass(char[] packageName, char[] className, char[] completionName, int modifiers, int completionStart, int completionEnd) {
// Remove completion on generated class name or generated global variable class name
if (CharOperation.equals(packageName, CodeSnippetToCuMapper.this.packageName)
&& (CharOperation.equals(className, CodeSnippetToCuMapper.this.className)
|| CharOperation.equals(className, CodeSnippetToCuMapper.this.varClassName))) return;
originalRequestor.acceptClass(packageName, className, completionName, modifiers, completionStart - startPosOffset, completionEnd - startPosOffset);
}
public void acceptError(IProblem error) {
error.setSourceLineNumber(error.getSourceLineNumber() - lineNumberOffset);
error.setSourceStart(error.getSourceStart() - startPosOffset);
error.setSourceEnd(error.getSourceEnd() - startPosOffset);
originalRequestor.acceptError(error);
}
public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] name, char[] typePackageName, char[] typeName, char[] completionName, int modifiers, int completionStart, int completionEnd) {
originalRequestor.acceptField(declaringTypePackageName, declaringTypeName, name, typePackageName, typeName, completionName, modifiers, completionStart - startPosOffset, completionEnd - startPosOffset);
}
public void acceptInterface(char[] packageName, char[] interfaceName, char[] completionName, int modifiers, int completionStart, int completionEnd) {
originalRequestor.acceptInterface(packageName, interfaceName, completionName, modifiers, completionStart - startPosOffset, completionEnd - startPosOffset);
}
public void acceptKeyword(char[] keywordName, int completionStart, int completionEnd) {
originalRequestor.acceptKeyword(keywordName, completionStart - startPosOffset, completionEnd - startPosOffset);
}
public void acceptLabel(char[] labelName, int completionStart, int completionEnd) {
originalRequestor.acceptLabel(labelName, completionStart - startPosOffset, completionEnd - startPosOffset);
}
public void acceptLocalVariable(char[] name, char[] typePackageName, char[] typeName, int modifiers, int completionStart, int completionEnd) {
originalRequestor.acceptLocalVariable(name, typePackageName, typeName, modifiers, completionStart - startPosOffset, completionEnd - startPosOffset);
}
public void acceptMethod(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, char[] returnTypePackageName, char[] returnTypeName, char[] completionName, int modifiers, int completionStart, int completionEnd) {
// Remove completion on generated method
if (CharOperation.equals(declaringTypePackageName, CodeSnippetToCuMapper.this.packageName)
&& CharOperation.equals(declaringTypeName, CodeSnippetToCuMapper.this.className)
&& CharOperation.equals(selector, "run"/*nonNLS*/.toCharArray())) return;
originalRequestor.acceptMethod(declaringTypePackageName, declaringTypeName, selector, parameterPackageNames, parameterTypeNames, returnTypePackageName, returnTypeName, completionName, modifiers, completionStart - startPosOffset, completionEnd - startPosOffset);
}
public void acceptModifier(char[] modifierName, int completionStart, int completionEnd) {
originalRequestor.acceptModifier(modifierName, completionStart - startPosOffset, completionEnd - startPosOffset);
}
public void acceptPackage(char[] packageName, char[] completionName, int completionStart, int completionEnd) {
originalRequestor.acceptPackage(packageName, completionName, completionStart - startPosOffset, completionEnd - startPosOffset);
}
public void acceptType(char[] packageName, char[] typeName, char[] completionName, int completionStart, int completionEnd) {
// Remove completion on generated class name or generated global variable class name
if (CharOperation.equals(packageName, CodeSnippetToCuMapper.this.packageName)
&& (CharOperation.equals(className, CodeSnippetToCuMapper.this.className)
|| CharOperation.equals(className, CodeSnippetToCuMapper.this.varClassName))) return;
originalRequestor.acceptType(packageName, typeName, completionName, completionStart - startPosOffset, completionEnd - startPosOffset);
}
};
}
public char[] getCUSource() {
if (this.cuSource == null) {
buildCUSource();
}
return this.cuSource;
}
/**
* Returns the type of evaluation that corresponds to the given line number in the generated compilation unit.
*/
public int getEvaluationType(int lineNumber) {
int currentLine = 1;
// check package declaration
if (this.packageName != null && this.packageName.length != 0) {
if (lineNumber == 1) {
return EvaluationResult.T_PACKAGE;
}
currentLine++;
}
// check imports
char[][] imports = this.imports;
if ((currentLine <= lineNumber) && (lineNumber < (currentLine + imports.length))) {
return EvaluationResult.T_IMPORT;
}
currentLine += imports.length + 1; // + 1 to skip the class declaration line
// check generated fields
currentLine +=
(this.declaringTypeName == null ? 0 : 1)
+ (this.localVarNames == null ? 0 : this.localVarNames.length);
if (currentLine > lineNumber) {
return EvaluationResult.T_INTERNAL;
}
currentLine ++; // + 1 to skip the method declaration line
// check code snippet
if (currentLine >= this.lineNumberOffset) {
return EvaluationResult.T_CODE_SNIPPET;
}
// default
return EvaluationResult.T_INTERNAL;
}
/**
* Returns the import defined at the given line number.
*/
public char[] getImport(int lineNumber) {
int importStartLine = this.lineNumberOffset - 2 - this.imports.length;
return this.imports[lineNumber - importStartLine];
}
/**
* Returns a selection requestor that wraps the given requestor and shift the problems
* according to the start offset and line number offset of the code snippet in the generated compilation unit.
*/
public ISelectionRequestor getSelectionRequestor(final ISelectionRequestor originalRequestor) {
final int startPosOffset = this.startPosOffset;
final int lineNumberOffset = this.lineNumberOffset;
return new ISelectionRequestor() {
public void acceptClass(char[] packageName, char[] className, boolean needQualification) {
originalRequestor.acceptClass(packageName, className, needQualification);
}
public void acceptError(IProblem error) {
error.setSourceLineNumber(error.getSourceLineNumber() - lineNumberOffset);
error.setSourceStart(error.getSourceStart() - startPosOffset);
error.setSourceEnd(error.getSourceEnd() - startPosOffset);
originalRequestor.acceptError(error);
}
public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] name) {
originalRequestor.acceptField(declaringTypePackageName, declaringTypeName, name);
}
public void acceptInterface(char[] packageName, char[] interfaceName, boolean needQualification) {
originalRequestor.acceptInterface(packageName, interfaceName, needQualification);
}
public void acceptMethod(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames) {
originalRequestor.acceptMethod(declaringTypePackageName, declaringTypeName, selector, parameterPackageNames, parameterTypeNames);
}
public void acceptPackage(char[] packageName) {
originalRequestor.acceptPackage(packageName);
}
};
}
}