001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.eval;
011:
012: import java.util.Locale;
013: import java.util.Map;
014:
015: import org.eclipse.jdt.core.CompletionRequestor;
016: import org.eclipse.jdt.core.IJavaProject;
017: import org.eclipse.jdt.core.compiler.*;
018: import org.eclipse.jdt.internal.codeassist.CompletionEngine;
019: import org.eclipse.jdt.internal.codeassist.ISelectionRequestor;
020: import org.eclipse.jdt.internal.codeassist.SelectionEngine;
021: import org.eclipse.jdt.internal.compiler.ClassFile;
022: import org.eclipse.jdt.internal.compiler.IProblemFactory;
023: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
024: import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
025: import org.eclipse.jdt.internal.compiler.env.IBinaryType;
026: import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
027: import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
028: import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
029: import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
030: import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
031: import org.eclipse.jdt.internal.core.SearchableEnvironment;
032: import org.eclipse.jdt.internal.core.util.Util;
033:
034: /**
035: * @see org.eclipse.jdt.core.eval.IEvaluationContext
036: */
037: public class EvaluationContext implements EvaluationConstants,
038: SuffixConstants {
039: /**
040: * Whether timing information should be output to the stdout
041: */
042: static final boolean TIMING = false;
043:
044: /**
045: * Global counters so that several evaluation context can deploy on the same runtime.
046: */
047: static int VAR_CLASS_COUNTER = 0;
048: static int CODE_SNIPPET_COUNTER = 0;
049:
050: GlobalVariable[] variables;
051: int variableCount;
052: char[][] imports;
053: char[] packageName;
054: boolean varsChanged;
055: VariablesInfo installedVars;
056: IBinaryType codeSnippetBinary;
057: String lineSeparator;
058:
059: /* do names implicitly refer to a given type */
060: char[] declaringTypeName;
061: int[] localVariableModifiers;
062: char[][] localVariableTypeNames;
063: char[][] localVariableNames;
064:
065: /* can 'this' be used in this context */
066: boolean isStatic;
067: boolean isConstructorCall;
068:
069: /**
070: * Creates a new evaluation context.
071: */
072: public EvaluationContext() {
073: this .variables = new GlobalVariable[5];
074: this .variableCount = 0;
075: this .imports = CharOperation.NO_CHAR_CHAR;
076: this .packageName = CharOperation.NO_CHAR;
077: this .varsChanged = true;
078: this .isStatic = true;
079: this .isConstructorCall = false;
080: this .lineSeparator = org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR; // default value
081: }
082:
083: /**
084: * Returns the global variables of this evaluation context in the order they were created in.
085: */
086: public GlobalVariable[] allVariables() {
087: GlobalVariable[] result = new GlobalVariable[this .variableCount];
088: System.arraycopy(this .variables, 0, result, 0,
089: this .variableCount);
090: return result;
091: }
092:
093: /**
094: * Computes a completion at the specified position of the given code snippet.
095: * (Note that this evaluation context's VM doesn't need to be running.)
096: *
097: * @param environment
098: * used to resolve type/package references and search for types/packages
099: * based on partial names.
100: *
101: * @param requestor
102: * since the engine might produce answers of various forms, the engine
103: * is associated with a requestor able to accept all possible completions.
104: *
105: * @param options
106: * set of options used to configure the code assist engine.
107: */
108: public void complete(char[] codeSnippet, int completionPosition,
109: SearchableEnvironment environment,
110: CompletionRequestor requestor, Map options,
111: IJavaProject project) {
112: try {
113: IRequestor variableRequestor = new IRequestor() {
114: public boolean acceptClassFiles(ClassFile[] classFiles,
115: char[] codeSnippetClassName) {
116: // Do nothing
117: return true;
118: }
119:
120: public void acceptProblem(CategorizedProblem problem,
121: char[] fragmentSource, int fragmentKind) {
122: // Do nothing
123: }
124: };
125: this .evaluateVariables(environment, options,
126: variableRequestor, new DefaultProblemFactory(Locale
127: .getDefault()));
128: } catch (InstallException e) {
129: // Do nothing
130: }
131: final char[] className = "CodeSnippetCompletion".toCharArray(); //$NON-NLS-1$
132: final CodeSnippetToCuMapper mapper = new CodeSnippetToCuMapper(
133: codeSnippet, this .packageName, this .imports, className,
134: this .installedVars == null ? null
135: : this .installedVars.className,
136: this .localVariableNames, this .localVariableTypeNames,
137: this .localVariableModifiers, this .declaringTypeName,
138: this .lineSeparator);
139: ICompilationUnit sourceUnit = new ICompilationUnit() {
140: public char[] getFileName() {
141: return CharOperation.concat(className, Util
142: .defaultJavaExtension().toCharArray());
143: }
144:
145: public char[] getContents() {
146: return mapper
147: .getCUSource(EvaluationContext.this .lineSeparator);
148: }
149:
150: public char[] getMainTypeName() {
151: return className;
152: }
153:
154: public char[][] getPackageName() {
155: return null;
156: }
157: };
158:
159: CompletionEngine engine = new CompletionEngine(environment,
160: mapper.getCompletionRequestor(requestor), options,
161: project);
162:
163: if (this .installedVars != null) {
164: IBinaryType binaryType = this .getRootCodeSnippetBinary();
165: if (binaryType != null) {
166: engine.lookupEnvironment.cacheBinaryType(binaryType,
167: null /*no access restriction*/);
168: }
169:
170: ClassFile[] classFiles = installedVars.classFiles;
171: for (int i = 0; i < classFiles.length; i++) {
172: ClassFile classFile = classFiles[i];
173: IBinaryType binary = null;
174: try {
175: binary = new ClassFileReader(classFile.getBytes(),
176: null);
177: } catch (ClassFormatException e) {
178: e.printStackTrace(); // Should never happen since we compiled this type
179: }
180: engine.lookupEnvironment
181: .cacheBinaryType(binary, null /*no access restriction*/);
182: }
183: }
184:
185: engine.complete(sourceUnit, mapper.startPosOffset
186: + completionPosition, mapper.startPosOffset);
187: }
188:
189: /**
190: * Deletes the given variable from this evaluation context. This will take effect in the target VM only
191: * the next time global variables are installed.
192: */
193: public void deleteVariable(GlobalVariable variable) {
194: GlobalVariable[] vars = this .variables;
195: int index = -1;
196: for (int i = 0; i < this .variableCount; i++) {
197: if (vars[i].equals(variable)) {
198: index = i;
199: break;
200: }
201: }
202: if (index == -1) {
203: return;
204: }
205: int elementCount = this .variableCount--;
206: int j = elementCount - index - 1;
207: if (j > 0) {
208: System.arraycopy(vars, index + 1, vars, index, j);
209: }
210: vars[elementCount - 1] = null;
211: this .varsChanged = true;
212: }
213:
214: private void deployCodeSnippetClassIfNeeded(IRequestor requestor) {
215: if (this .codeSnippetBinary == null) {
216: // Deploy CodeSnippet class (only once)
217: requestor.acceptClassFiles(
218: new ClassFile[] { new ClassFile() {
219: public byte[] getBytes() {
220: return getCodeSnippetBytes();
221: }
222:
223: public char[][] getCompoundName() {
224: return EvaluationConstants.ROOT_COMPOUND_NAME;
225: }
226: } }, null);
227: }
228: }
229:
230: /**
231: * @see org.eclipse.jdt.core.eval.IEvaluationContext
232: * @exception org.eclipse.jdt.internal.eval.InstallException if the code snippet class files could not be deployed.
233: */
234: public void evaluate(char[] codeSnippet,
235: char[][] contextLocalVariableTypeNames,
236: char[][] contextLocalVariableNames,
237: int[] contextLocalVariableModifiers,
238: char[] contextDeclaringTypeName, boolean contextIsStatic,
239: boolean contextIsConstructorCall,
240: INameEnvironment environment, Map options,
241: final IRequestor requestor, IProblemFactory problemFactory)
242: throws InstallException {
243:
244: // Initialialize context
245: this .localVariableTypeNames = contextLocalVariableTypeNames;
246: this .localVariableNames = contextLocalVariableNames;
247: this .localVariableModifiers = contextLocalVariableModifiers;
248: this .declaringTypeName = contextDeclaringTypeName;
249: this .isStatic = contextIsStatic;
250: this .isConstructorCall = contextIsConstructorCall;
251:
252: this .deployCodeSnippetClassIfNeeded(requestor);
253:
254: try {
255: // Install new variables if needed
256: class ForwardingRequestor implements IRequestor {
257: boolean hasErrors = false;
258:
259: public boolean acceptClassFiles(ClassFile[] classFiles,
260: char[] codeSnippetClassName) {
261: return requestor.acceptClassFiles(classFiles,
262: codeSnippetClassName);
263: }
264:
265: public void acceptProblem(CategorizedProblem problem,
266: char[] fragmentSource, int fragmentKind) {
267: requestor.acceptProblem(problem, fragmentSource,
268: fragmentKind);
269: if (problem.isError()) {
270: this .hasErrors = true;
271: }
272: }
273: }
274: ForwardingRequestor forwardingRequestor = new ForwardingRequestor();
275: if (this .varsChanged) {
276: evaluateVariables(environment, options,
277: forwardingRequestor, problemFactory);
278: }
279:
280: // Compile code snippet if there was no errors while evaluating the variables
281: if (!forwardingRequestor.hasErrors) {
282: Evaluator evaluator = new CodeSnippetEvaluator(
283: codeSnippet, this , environment, options,
284: requestor, problemFactory);
285: ClassFile[] classes = null;
286: if (TIMING) {
287: long start = System.currentTimeMillis();
288: classes = evaluator.getClasses();
289: System.out
290: .println("Time to compile [" + new String(codeSnippet) + "] was " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
291: } else {
292: classes = evaluator.getClasses();
293: }
294: // Send code snippet on target
295: if (classes != null && classes.length > 0) {
296: char[] simpleClassName = evaluator.getClassName();
297: char[] pkgName = this .getPackageName();
298: char[] qualifiedClassName = pkgName.length == 0 ? simpleClassName
299: : CharOperation.concat(pkgName,
300: simpleClassName, '.');
301: CODE_SNIPPET_COUNTER++;
302: requestor.acceptClassFiles(classes,
303: qualifiedClassName);
304: }
305: }
306: } finally {
307: // Reinitialize context to default values
308: this .localVariableTypeNames = null;
309: this .localVariableNames = null;
310: this .localVariableModifiers = null;
311: this .declaringTypeName = null;
312: this .isStatic = true;
313: this .isConstructorCall = false;
314: }
315: }
316:
317: /**
318: * @see org.eclipse.jdt.core.eval.IEvaluationContext
319: * @exception org.eclipse.jdt.internal.eval.InstallException if the code snippet class files could not be deployed.
320: */
321: public void evaluate(char[] codeSnippet,
322: INameEnvironment environment, Map options,
323: final IRequestor requestor, IProblemFactory problemFactory)
324: throws InstallException {
325: this .evaluate(codeSnippet, null, null, null, null, true, false,
326: environment, options, requestor, problemFactory);
327: }
328:
329: /**
330: * @see org.eclipse.jdt.core.eval.IEvaluationContext
331: */
332: public void evaluateImports(INameEnvironment environment,
333: IRequestor requestor, IProblemFactory problemFactory) {
334: for (int i = 0; i < this .imports.length; i++) {
335: CategorizedProblem[] problems = new CategorizedProblem[] { null };
336: char[] importDeclaration = this .imports[i];
337: char[][] splitDeclaration = CharOperation.splitOn('.',
338: importDeclaration);
339: int splitLength = splitDeclaration.length;
340: if (splitLength > 0) {
341: char[] pkgName = splitDeclaration[splitLength - 1];
342: if (pkgName.length == 1 && pkgName[0] == '*') {
343: char[][] parentName;
344: switch (splitLength) {
345: case 1:
346: parentName = null;
347: break;
348: case 2:
349: parentName = null;
350: pkgName = splitDeclaration[splitLength - 2];
351: break;
352: default:
353: parentName = CharOperation.subarray(
354: splitDeclaration, 0, splitLength - 2);
355: pkgName = splitDeclaration[splitLength - 2];
356: }
357: if (!environment.isPackage(parentName, pkgName)) {
358: String[] arguments = new String[] { new String(
359: importDeclaration) };
360: problems[0] = problemFactory.createProblem(
361: importDeclaration,
362: IProblem.ImportNotFound, arguments,
363: arguments, ProblemSeverities.Warning,
364: 0, importDeclaration.length - 1, i, 0);
365: }
366: } else {
367: if (environment.findType(splitDeclaration) == null) {
368: String[] arguments = new String[] { new String(
369: importDeclaration) };
370: problems[0] = problemFactory.createProblem(
371: importDeclaration,
372: IProblem.ImportNotFound, arguments,
373: arguments, ProblemSeverities.Warning,
374: 0, importDeclaration.length - 1, i, 0);
375: }
376: }
377: } else {
378: String[] arguments = new String[] { new String(
379: importDeclaration) };
380: problems[0] = problemFactory.createProblem(
381: importDeclaration, IProblem.ImportNotFound,
382: arguments, arguments,
383: ProblemSeverities.Warning, 0,
384: importDeclaration.length - 1, i, 0);
385: }
386: if (problems[0] != null) {
387: requestor.acceptProblem(problems[0], importDeclaration,
388: EvaluationResult.T_IMPORT);
389: }
390: }
391: }
392:
393: /**
394: * @see org.eclipse.jdt.core.eval.IEvaluationContext
395: * @exception org.eclipse.jdt.internal.eval.InstallException if the code snippet class files could not be deployed.
396: * @exception java.lang.IllegalArgumentException if the global has not been installed yet.
397: */
398: public void evaluateVariable(GlobalVariable variable,
399: INameEnvironment environment, Map options,
400: IRequestor requestor, IProblemFactory problemFactory)
401: throws InstallException {
402: this .evaluate(variable.getName(), environment, options,
403: requestor, problemFactory);
404: }
405:
406: /**
407: * @see org.eclipse.jdt.core.eval.IEvaluationContext
408: * @exception org.eclipse.jdt.internal.eval.InstallException if the code snippet class files could not be deployed.
409: */
410: public void evaluateVariables(INameEnvironment environment,
411: Map options, IRequestor requestor,
412: IProblemFactory problemFactory) throws InstallException {
413: this .deployCodeSnippetClassIfNeeded(requestor);
414: VariablesEvaluator evaluator = new VariablesEvaluator(this ,
415: environment, options, requestor, problemFactory);
416: ClassFile[] classes = evaluator.getClasses();
417: if (classes != null) {
418: if (classes.length > 0) {
419: // Sort classes so that enclosing types are cached before nested types
420: // otherwise an AbortCompilation is thrown in 1.5 mode since the enclosing type
421: // is needed to resolve a nested type
422: Util.sort(classes, new Util.Comparer() {
423: public int compare(Object a, Object b) {
424: if (a == b)
425: return 0;
426: ClassFile enclosing = ((ClassFile) a).enclosingClassFile;
427: while (enclosing != null) {
428: if (enclosing == b)
429: return 1;
430: enclosing = enclosing.enclosingClassFile;
431: }
432: return -1;
433: }
434: });
435:
436: // Send classes
437: if (!requestor.acceptClassFiles(classes, null)) {
438: throw new InstallException();
439: }
440:
441: // Remember that the variables have been installed
442: int count = this .variableCount;
443: GlobalVariable[] variablesCopy = new GlobalVariable[count];
444: System.arraycopy(this .variables, 0, variablesCopy, 0,
445: count);
446: this .installedVars = new VariablesInfo(evaluator
447: .getPackageName(), evaluator.getClassName(),
448: classes, variablesCopy, count);
449: VAR_CLASS_COUNTER++;
450: }
451: this .varsChanged = false;
452: }
453: }
454:
455: /**
456: * Returns the bytes of the CodeSnippet class.
457: * Generated using the following code snippet:
458: [java.io.BufferedWriter writer = new java.io.BufferedWriter(new java.io.FileWriter("d:/temp/CodeSnippet.java"));
459: writer.write(org.eclipse.jdt.internal.eval.EvaluationContext.getCodeSnippetSource());
460: writer.close();
461: org.eclipse.jdt.internal.compiler.batch.Main.compile(
462: "d:/temp/CodeSnippet.java -d d:/temp -classpath d:/jdk1.2.2/jre/lib/rt.jar -verbose");
463: java.io.FileInputStream reader = new java.io.FileInputStream("d:/temp/org/eclipse/jdt/internal/eval/target/CodeSnippet.class");
464: byte[] bytes = org.eclipse.jdt.internal.core.Util.readContentsAsBytes(reader);
465: reader.close();
466: StringBuffer buffer = new StringBuffer();
467: buffer.append("private byte[] getCodeSnippetBytes() {\n");
468: buffer.append(" return new byte[] {\n");
469: buffer.append(" ");
470: for (int i = 0; i < bytes.length; i++) {
471: buffer.append(bytes[i]);
472: if (i == bytes.length - 1) {
473: buffer.append("\n");
474: } else {
475: buffer.append(", ");
476: }
477: }
478: buffer.append(" };\n");
479: buffer.append("}");
480: buffer.toString()
481: ]
482: */
483: byte[] getCodeSnippetBytes() {
484: return new byte[] { -54, -2, -70, -66, 0, 3, 0, 45, 0, 35, 1,
485: 0, 48, 111, 114, 103, 47, 101, 99, 108, 105, 112, 115,
486: 101, 47, 106, 100, 116, 47, 105, 110, 116, 101, 114,
487: 110, 97, 108, 47, 101, 118, 97, 108, 47, 116, 97, 114,
488: 103, 101, 116, 47, 67, 111, 100, 101, 83, 110, 105,
489: 112, 112, 101, 116, 7, 0, 1, 1, 0, 16, 106, 97, 118,
490: 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99,
491: 116, 7, 0, 3, 1, 0, 10, 114, 101, 115, 117, 108, 116,
492: 84, 121, 112, 101, 1, 0, 17, 76, 106, 97, 118, 97, 47,
493: 108, 97, 110, 103, 47, 67, 108, 97, 115, 115, 59, 1, 0,
494: 11, 114, 101, 115, 117, 108, 116, 86, 97, 108, 117,
495: 101, 1, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110,
496: 103, 47, 79, 98, 106, 101, 99, 116, 59, 1, 0, 7, 99,
497: 108, 97, 115, 115, 36, 48, 1, 0, 9, 83, 121, 110, 116,
498: 104, 101, 116, 105, 99, 1, 0, 6, 60, 105, 110, 105,
499: 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100,
500: 101, 12, 0, 11, 0, 12, 10, 0, 4, 0, 14, 1, 0, 14, 106,
501: 97, 118, 97, 47, 108, 97, 110, 103, 47, 86, 111, 105,
502: 100, 7, 0, 16, 1, 0, 4, 84, 89, 80, 69, 12, 0, 18, 0,
503: 6, 9, 0, 17, 0, 19, 12, 0, 5, 0, 6, 9, 0, 2, 0, 21, 12,
504: 0, 7, 0, 8, 9, 0, 2, 0, 23, 1, 0, 15, 76, 105, 110,
505: 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101,
506: 1, 0, 13, 103, 101, 116, 82, 101, 115, 117, 108, 116,
507: 84, 121, 112, 101, 1, 0, 19, 40, 41, 76, 106, 97, 118,
508: 97, 47, 108, 97, 110, 103, 47, 67, 108, 97, 115, 115,
509: 59, 1, 0, 14, 103, 101, 116, 82, 101, 115, 117, 108,
510: 116, 86, 97, 108, 117, 101, 1, 0, 20, 40, 41, 76, 106,
511: 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106,
512: 101, 99, 116, 59, 1, 0, 3, 114, 117, 110, 1, 0, 9, 115,
513: 101, 116, 82, 101, 115, 117, 108, 116, 1, 0, 38, 40,
514: 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79,
515: 98, 106, 101, 99, 116, 59, 76, 106, 97, 118, 97, 47,
516: 108, 97, 110, 103, 47, 67, 108, 97, 115, 115, 59, 41,
517: 86, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108,
518: 101, 1, 0, 16, 67, 111, 100, 101, 83, 110, 105, 112,
519: 112, 101, 116, 46, 106, 97, 118, 97, 0, 33, 0, 2, 0, 4,
520: 0, 0, 0, 3, 0, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 7, 0, 8,
521: 0, 0, 0, 8, 0, 9, 0, 6, 0, 1, 0, 10, 0, 0, 0, 0, 0, 5,
522: 0, 1, 0, 11, 0, 12, 0, 1, 0, 13, 0, 0, 0, 53, 0, 2, 0,
523: 1, 0, 0, 0, 17, 42, -73, 0, 15, 42, -78, 0, 20, -75, 0,
524: 22, 42, 1, -75, 0, 24, -79, 0, 0, 0, 1, 0, 25, 0, 0, 0,
525: 18, 0, 4, 0, 0, 0, 17, 0, 4, 0, 18, 0, 11, 0, 19, 0,
526: 16, 0, 17, 0, 1, 0, 26, 0, 27, 0, 1, 0, 13, 0, 0, 0,
527: 29, 0, 1, 0, 1, 0, 0, 0, 5, 42, -76, 0, 22, -80, 0, 0,
528: 0, 1, 0, 25, 0, 0, 0, 6, 0, 1, 0, 0, 0, 24, 0, 1, 0,
529: 28, 0, 29, 0, 1, 0, 13, 0, 0, 0, 29, 0, 1, 0, 1, 0, 0,
530: 0, 5, 42, -76, 0, 24, -80, 0, 0, 0, 1, 0, 25, 0, 0, 0,
531: 6, 0, 1, 0, 0, 0, 30, 0, 1, 0, 30, 0, 12, 0, 1, 0, 13,
532: 0, 0, 0, 25, 0, 0, 0, 1, 0, 0, 0, 1, -79, 0, 0, 0, 1,
533: 0, 25, 0, 0, 0, 6, 0, 1, 0, 0, 0, 36, 0, 1, 0, 31, 0,
534: 32, 0, 1, 0, 13, 0, 0, 0, 43, 0, 2, 0, 3, 0, 0, 0, 11,
535: 42, 43, -75, 0, 24, 42, 44, -75, 0, 22, -79, 0, 0, 0,
536: 1, 0, 25, 0, 0, 0, 14, 0, 3, 0, 0, 0, 42, 0, 5, 0, 43,
537: 0, 10, 0, 41, 0, 1, 0, 33, 0, 0, 0, 2, 0, 34 };
538: }
539:
540: /**
541: * Returns the source of the CodeSnippet class.
542: * This is used to generate the binary of the CodeSnippetClass
543: */
544: public static String getCodeSnippetSource() {
545: return "package org.eclipse.jdt.internal.eval.target;\n" + //$NON-NLS-1$
546: "\n"
547: + //$NON-NLS-1$
548: "/*\n"
549: + //$NON-NLS-1$
550: " * (c) Copyright IBM Corp. 2000, 2001.\n"
551: + //$NON-NLS-1$
552: " * All Rights Reserved.\n"
553: + //$NON-NLS-1$
554: " */\n"
555: + //$NON-NLS-1$
556: "/**\n"
557: + //$NON-NLS-1$
558: " * The root of all code snippet classes. Code snippet classes\n"
559: + //$NON-NLS-1$
560: " * are supposed to overide the run() method.\n"
561: + //$NON-NLS-1$
562: " * <p>\n"
563: + //$NON-NLS-1$
564: " * IMPORTANT NOTE:\n"
565: + //$NON-NLS-1$
566: " * All methods in this class must be public since this class is going to be loaded by the\n"
567: + //$NON-NLS-1$
568: " * bootstrap class loader, and the other code snippet support classes might be loaded by \n"
569: + //$NON-NLS-1$
570: " * another class loader (so their runtime packages are going to be different).\n"
571: + //$NON-NLS-1$
572: " */\n"
573: + //$NON-NLS-1$
574: "public class CodeSnippet {\n"
575: + //$NON-NLS-1$
576: " private Class resultType = void.class;\n"
577: + //$NON-NLS-1$
578: " private Object resultValue = null;\n"
579: + //$NON-NLS-1$
580: "/**\n"
581: + //$NON-NLS-1$
582: " * Returns the result type of the code snippet evaluation.\n"
583: + //$NON-NLS-1$
584: " */\n"
585: + //$NON-NLS-1$
586: "public Class getResultType() {\n"
587: + //$NON-NLS-1$
588: " return this.resultType;\n"
589: + //$NON-NLS-1$
590: "}\n"
591: + //$NON-NLS-1$
592: "/**\n"
593: + //$NON-NLS-1$
594: " * Returns the result value of the code snippet evaluation.\n"
595: + //$NON-NLS-1$
596: " */\n"
597: + //$NON-NLS-1$
598: "public Object getResultValue() {\n"
599: + //$NON-NLS-1$
600: " return this.resultValue;\n"
601: + //$NON-NLS-1$
602: "}\n"
603: + //$NON-NLS-1$
604: "/**\n"
605: + //$NON-NLS-1$
606: " * The code snippet. Subclasses must override this method with a transformed code snippet\n"
607: + //$NON-NLS-1$
608: " * that stores the result using setResult(Class, Object).\n"
609: + //$NON-NLS-1$
610: " */\n"
611: + //$NON-NLS-1$
612: "public void run() {\n"
613: + //$NON-NLS-1$
614: "}\n"
615: + //$NON-NLS-1$
616: "/**\n"
617: + //$NON-NLS-1$
618: " * Stores the result type and value of the code snippet evaluation.\n"
619: + //$NON-NLS-1$
620: " */\n"
621: + //$NON-NLS-1$
622: "public void setResult(Object someResultValue, Class someResultType) {\n"
623: + //$NON-NLS-1$
624: " this.resultValue = someResultValue;\n" + //$NON-NLS-1$
625: " this.resultType = someResultType;\n" + //$NON-NLS-1$
626: "}\n" + //$NON-NLS-1$
627: "}\n"; //$NON-NLS-1$
628: }
629:
630: /**
631: * Returns the imports of this evaluation context. An import is the name of a package
632: * or the fully qualified name of a type as defined in the import statement of
633: * a compilation unit.
634: */
635: public char[][] getImports() {
636: return this .imports;
637: }
638:
639: /**
640: * Returns the dot-separated name of the package code snippets are run into.
641: * Returns an empty array for the default package. This is the default if
642: * the package name has never been set.
643: */
644: public char[] getPackageName() {
645: return this .packageName;
646: }
647:
648: /**
649: * Return the binary for the root code snippet class (ie. org.eclipse.jdt.internal.eval.target.CodeSnippet).
650: */
651: IBinaryType getRootCodeSnippetBinary() {
652: if (this .codeSnippetBinary == null) {
653: this .codeSnippetBinary = new CodeSnippetSkeleton();
654: }
655: return this .codeSnippetBinary;
656: }
657:
658: public char[] getVarClassName() {
659: if (installedVars == null)
660: return CharOperation.NO_CHAR;
661: return CharOperation.concat(installedVars.packageName,
662: installedVars.className, '.');
663: }
664:
665: /**
666: * Creates a new global variable with the given name, type and initializer.
667: * If the variable is not initialized, the initializer can be null.
668: * Note that this doesn't install it to this evaluation context's VM.
669: *
670: * @see GlobalVariable
671: */
672: public GlobalVariable newVariable(char[] typeName, char[] name,
673: char[] initializer) {
674: GlobalVariable var = new GlobalVariable(typeName, name,
675: initializer);
676: if (this .variableCount >= this .variables.length) // assume variables is never empty
677: System
678: .arraycopy(
679: this .variables,
680: 0,
681: this .variables = new GlobalVariable[this .variableCount * 2],
682: 0, this .variableCount);
683: this .variables[this .variableCount++] = var;
684: this .varsChanged = true;
685: return var;
686: }
687:
688: /**
689: * Computes the selection at the specified positions of the given code snippet.
690: * (Note that this evaluation context's VM doesn't need to be running.)
691: * @param codeSnippet char[]
692: * The code snipper source
693: *
694: * @param selectionSourceStart int
695: *
696: * @param selectionSourceEnd int
697: *
698: * @param environment org.eclipse.jdt.internal.core.SearchableEnvironment
699: * used to resolve type/package references and search for types/packages
700: * based on partial names.
701: *
702: * @param requestor org.eclipse.jdt.internal.codeassist.ISelectionRequestor
703: * since the engine might produce answers of various forms, the engine
704: * is associated with a requestor able to accept all possible selections.
705: *
706: * @param options java.util.Map
707: * set of options used to configure the code assist engine.
708: */
709: public void select(char[] codeSnippet, int selectionSourceStart,
710: int selectionSourceEnd, SearchableEnvironment environment,
711: ISelectionRequestor requestor, Map options) {
712:
713: final char[] className = "CodeSnippetSelection".toCharArray(); //$NON-NLS-1$
714: final CodeSnippetToCuMapper mapper = new CodeSnippetToCuMapper(
715: codeSnippet, this .packageName, this .imports, className,
716: this .installedVars == null ? null
717: : this .installedVars.className,
718: this .localVariableNames, this .localVariableTypeNames,
719: this .localVariableModifiers, this .declaringTypeName,
720: this .lineSeparator);
721: ICompilationUnit sourceUnit = new ICompilationUnit() {
722: public char[] getFileName() {
723: return CharOperation.concat(className, Util
724: .defaultJavaExtension().toCharArray());
725: }
726:
727: public char[] getContents() {
728: return mapper
729: .getCUSource(EvaluationContext.this .lineSeparator);
730: }
731:
732: public char[] getMainTypeName() {
733: return className;
734: }
735:
736: public char[][] getPackageName() {
737: return null;
738: }
739: };
740: SelectionEngine engine = new SelectionEngine(environment,
741: mapper.getSelectionRequestor(requestor), options);
742: engine.select(sourceUnit, mapper.startPosOffset
743: + selectionSourceStart, mapper.startPosOffset
744: + selectionSourceEnd);
745: }
746:
747: /**
748: * Sets the imports of this evaluation context. An import is the name of a package
749: * or the fully qualified name of a type as defined in the import statement of
750: * a compilation unit (see the Java Language Specifications for more details).
751: */
752: public void setImports(char[][] imports) {
753: this .imports = imports;
754: this .varsChanged = true; // this may change the visibility of the variable's types
755: }
756:
757: /**
758: * Sets the line separator used by this evaluation context.
759: */
760: public void setLineSeparator(String lineSeparator) {
761: this .lineSeparator = lineSeparator;
762: }
763:
764: /**
765: * Sets the dot-separated name of the package code snippets are ran into.
766: * The default package name is an empty array.
767: */
768: public void setPackageName(char[] packageName) {
769: this .packageName = packageName;
770: this .varsChanged = true; // this may change the visibility of the variable's types
771: }
772: }
|