/******************************************************************************* * Copyright (c) 2000, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.eval; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.jdt.core.compiler.*; import org.eclipse.jdt.internal.compiler.ClassFile; import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.Compiler; import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; import org.eclipse.jdt.internal.compiler.ICompilerRequestor; import org.eclipse.jdt.internal.compiler.IProblemFactory; 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.core.util.Util; /** * A evaluator builds a compilation unit and compiles it into class files. * If the compilation unit has problems, reports the problems using the * requestor. */ public abstract class Evaluator { EvaluationContext context; INameEnvironment environment; Map options; IRequestor requestor; IProblemFactory problemFactory; /** * Creates a new evaluator. */ Evaluator(EvaluationContext context, INameEnvironment environment, Map options, IRequestor requestor, IProblemFactory problemFactory) { this.context = context; this.environment = environment; this.options = options; this.requestor = requestor; this.problemFactory = problemFactory; } /** * Adds the given problem to the corresponding evaluation result in the given table. If the evaluation * result doesn't exist yet, adds it in the table. Its evaluation id and evaluation type * are computed so that they correspond to the given problem. If it is found to be an internal problem, * then the evaluation id of the result is the given compilation unit source. */ protected abstract void addEvaluationResultForCompilationProblem(Map resultsByIDs,CategorizedProblem problem, char[] cuSource); /** * Returns the evaluation results that converts the given compilation result that has problems. * If the compilation result has more than one problem, then the problems are broken down so that * each evaluation result has the same evaluation id. */ protected EvaluationResult[] evaluationResultsForCompilationProblems(CompilationResult result, char[] cuSource) { // Break down the problems and group them by ids in evaluation results CategorizedProblem[] problems = result.getAllProblems(); HashMap resultsByIDs = new HashMap(5); for (int i = 0; i < problems.length; i++) { addEvaluationResultForCompilationProblem(resultsByIDs, problems[i], cuSource); } // Copy results int size = resultsByIDs.size(); EvaluationResult[] evalResults = new EvaluationResult[size]; Iterator results = resultsByIDs.values().iterator(); for (int i = 0; i < size; i++) { evalResults[i] = (EvaluationResult)results.next(); } return evalResults; } /** * Compiles and returns the class definitions for the current compilation unit. * Returns null if there are any errors. */ ClassFile[] getClasses() { final char[] source = getSource(); final ArrayList classDefinitions = new ArrayList(); // The requestor collects the class definitions and problems class CompilerRequestor implements ICompilerRequestor { boolean hasErrors = false; public void acceptResult(CompilationResult result) { if (result.hasProblems()) { EvaluationResult[] evalResults = evaluationResultsForCompilationProblems(result, source); for (int i = 0; i < evalResults.length; i++) { EvaluationResult evalResult = evalResults[i]; CategorizedProblem[] problems = evalResult.getProblems(); for (int j = 0; j < problems.length; j++) { Evaluator.this.requestor.acceptProblem(problems[j], evalResult.getEvaluationID(), evalResult.getEvaluationType()); } } } if (result.hasErrors()) { this.hasErrors = true; } else { ClassFile[] classFiles = result.getClassFiles(); for (int i = 0; i < classFiles.length; i++) { ClassFile classFile = classFiles[i]; /* char[] filename = classFile.fileName(); int length = filename.length; char[] relativeName = new char[length + 6]; System.arraycopy(filename, 0, relativeName, 0, length); System.arraycopy(".class".toCharArray(), 0, relativeName, length, 6); CharOperation.replace(relativeName, '/', java.io.File.separatorChar); ClassFile.writeToDisk("d:/test/snippet", new String(relativeName), classFile.getBytes()); String str = "d:/test/snippet" + "/" + new String(relativeName); System.out.println(org.eclipse.jdt.core.tools.classfmt.disassembler.ClassFileDisassembler.disassemble(str)); */ classDefinitions.add(classFile); } } } } // Compile compilation unit CompilerRequestor compilerRequestor = new CompilerRequestor(); Compiler compiler = getCompiler(compilerRequestor); compiler.compile(new ICompilationUnit[] {new ICompilationUnit() { public char[] getFileName() { // Name of class is name of CU return CharOperation.concat(Evaluator.this.getClassName(), Util.defaultJavaExtension().toCharArray()); } public char[] getContents() { return source; } public char[] getMainTypeName() { return Evaluator.this.getClassName(); } public char[][] getPackageName() { return null; } }}); if (compilerRequestor.hasErrors) { return null; } else { ClassFile[] result = new ClassFile[classDefinitions.size()]; classDefinitions.toArray(result); return result; } } /** * Returns the name of the current class. This is the simple name of the class. * This doesn't include the extension ".java" nor the name of the package. */ protected abstract char[] getClassName(); /** * Creates and returns a compiler for this evaluator. */ Compiler getCompiler(ICompilerRequestor compilerRequestor) { CompilerOptions compilerOptions = new CompilerOptions(this.options); compilerOptions.performMethodsFullRecovery = true; compilerOptions.performStatementsRecovery = true; return new Compiler( this.environment, DefaultErrorHandlingPolicies.exitAfterAllProblems(), compilerOptions, compilerRequestor, this.problemFactory); } /** * Builds and returns the source for the current compilation unit. */ protected abstract char[] getSource(); }