001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 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.ArrayList;
013: import java.util.HashMap;
014: import java.util.Iterator;
015: import java.util.Map;
016:
017: import org.eclipse.jdt.core.compiler.*;
018: import org.eclipse.jdt.internal.compiler.ClassFile;
019: import org.eclipse.jdt.internal.compiler.CompilationResult;
020: import org.eclipse.jdt.internal.compiler.Compiler;
021: import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
022: import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
023: import org.eclipse.jdt.internal.compiler.IProblemFactory;
024: import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
025: import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
026: import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
027: import org.eclipse.jdt.internal.core.util.Util;
028:
029: /**
030: * A evaluator builds a compilation unit and compiles it into class files.
031: * If the compilation unit has problems, reports the problems using the
032: * requestor.
033: */
034: public abstract class Evaluator {
035: EvaluationContext context;
036: INameEnvironment environment;
037: Map options;
038: IRequestor requestor;
039: IProblemFactory problemFactory;
040:
041: /**
042: * Creates a new evaluator.
043: */
044: Evaluator(EvaluationContext context, INameEnvironment environment,
045: Map options, IRequestor requestor,
046: IProblemFactory problemFactory) {
047: this .context = context;
048: this .environment = environment;
049: this .options = options;
050: this .requestor = requestor;
051: this .problemFactory = problemFactory;
052: }
053:
054: /**
055: * Adds the given problem to the corresponding evaluation result in the given table. If the evaluation
056: * result doesn't exist yet, adds it in the table. Its evaluation id and evaluation type
057: * are computed so that they correspond to the given problem. If it is found to be an internal problem,
058: * then the evaluation id of the result is the given compilation unit source.
059: */
060: protected abstract void addEvaluationResultForCompilationProblem(
061: Map resultsByIDs, CategorizedProblem problem,
062: char[] cuSource);
063:
064: /**
065: * Returns the evaluation results that converts the given compilation result that has problems.
066: * If the compilation result has more than one problem, then the problems are broken down so that
067: * each evaluation result has the same evaluation id.
068: */
069: protected EvaluationResult[] evaluationResultsForCompilationProblems(
070: CompilationResult result, char[] cuSource) {
071: // Break down the problems and group them by ids in evaluation results
072: CategorizedProblem[] problems = result.getAllProblems();
073: HashMap resultsByIDs = new HashMap(5);
074: for (int i = 0; i < problems.length; i++) {
075: addEvaluationResultForCompilationProblem(resultsByIDs,
076: problems[i], cuSource);
077: }
078:
079: // Copy results
080: int size = resultsByIDs.size();
081: EvaluationResult[] evalResults = new EvaluationResult[size];
082: Iterator results = resultsByIDs.values().iterator();
083: for (int i = 0; i < size; i++) {
084: evalResults[i] = (EvaluationResult) results.next();
085: }
086:
087: return evalResults;
088: }
089:
090: /**
091: * Compiles and returns the class definitions for the current compilation unit.
092: * Returns null if there are any errors.
093: */
094: ClassFile[] getClasses() {
095: final char[] source = getSource();
096: final ArrayList classDefinitions = new ArrayList();
097:
098: // The requestor collects the class definitions and problems
099: class CompilerRequestor implements ICompilerRequestor {
100: boolean hasErrors = false;
101:
102: public void acceptResult(CompilationResult result) {
103: if (result.hasProblems()) {
104: EvaluationResult[] evalResults = evaluationResultsForCompilationProblems(
105: result, source);
106: for (int i = 0; i < evalResults.length; i++) {
107: EvaluationResult evalResult = evalResults[i];
108: CategorizedProblem[] problems = evalResult
109: .getProblems();
110: for (int j = 0; j < problems.length; j++) {
111: Evaluator.this .requestor.acceptProblem(
112: problems[j], evalResult
113: .getEvaluationID(),
114: evalResult.getEvaluationType());
115: }
116: }
117: }
118: if (result.hasErrors()) {
119: this .hasErrors = true;
120: } else {
121: ClassFile[] classFiles = result.getClassFiles();
122: for (int i = 0; i < classFiles.length; i++) {
123: ClassFile classFile = classFiles[i];
124: /*
125:
126: char[] filename = classFile.fileName();
127: int length = filename.length;
128: char[] relativeName = new char[length + 6];
129: System.arraycopy(filename, 0, relativeName, 0, length);
130: System.arraycopy(".class".toCharArray(), 0, relativeName, length, 6);
131: CharOperation.replace(relativeName, '/', java.io.File.separatorChar);
132: ClassFile.writeToDisk("d:/test/snippet", new String(relativeName), classFile.getBytes());
133: String str = "d:/test/snippet" + "/" + new String(relativeName);
134: System.out.println(org.eclipse.jdt.core.tools.classfmt.disassembler.ClassFileDisassembler.disassemble(str));
135: */
136: classDefinitions.add(classFile);
137: }
138: }
139: }
140: }
141:
142: // Compile compilation unit
143: CompilerRequestor compilerRequestor = new CompilerRequestor();
144: Compiler compiler = getCompiler(compilerRequestor);
145: compiler
146: .compile(new ICompilationUnit[] { new ICompilationUnit() {
147: public char[] getFileName() {
148: // Name of class is name of CU
149: return CharOperation.concat(Evaluator.this
150: .getClassName(), Util
151: .defaultJavaExtension().toCharArray());
152: }
153:
154: public char[] getContents() {
155: return source;
156: }
157:
158: public char[] getMainTypeName() {
159: return Evaluator.this .getClassName();
160: }
161:
162: public char[][] getPackageName() {
163: return null;
164: }
165: } });
166: if (compilerRequestor.hasErrors) {
167: return null;
168: } else {
169: ClassFile[] result = new ClassFile[classDefinitions.size()];
170: classDefinitions.toArray(result);
171: return result;
172: }
173: }
174:
175: /**
176: * Returns the name of the current class. This is the simple name of the class.
177: * This doesn't include the extension ".java" nor the name of the package.
178: */
179: protected abstract char[] getClassName();
180:
181: /**
182: * Creates and returns a compiler for this evaluator.
183: */
184: Compiler getCompiler(ICompilerRequestor compilerRequestor) {
185: CompilerOptions compilerOptions = new CompilerOptions(
186: this .options);
187: compilerOptions.performMethodsFullRecovery = true;
188: compilerOptions.performStatementsRecovery = true;
189: return new Compiler(this .environment,
190: DefaultErrorHandlingPolicies.exitAfterAllProblems(),
191: compilerOptions, compilerRequestor, this .problemFactory);
192: }
193:
194: /**
195: * Builds and returns the source for the current compilation unit.
196: */
197: protected abstract char[] getSource();
198: }
|