/******************************************************************************* * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package net.sourceforge.phpdt.internal.core; import java.util.Locale; import java.util.Map; import net.sourceforge.phpdt.core.ICompilationUnit; import net.sourceforge.phpdt.core.IJavaElement; import net.sourceforge.phpdt.core.IJavaModelStatusConstants; import net.sourceforge.phpdt.core.IJavaProject; import net.sourceforge.phpdt.core.IPackageFragment; import net.sourceforge.phpdt.core.IProblemRequestor; import net.sourceforge.phpdt.core.JavaCore; import net.sourceforge.phpdt.core.JavaModelException; import net.sourceforge.phpdt.core.WorkingCopyOwner; import net.sourceforge.phpdt.core.compiler.CharOperation; import net.sourceforge.phpdt.core.compiler.IProblem; import net.sourceforge.phpdt.internal.compiler.CompilationResult; import net.sourceforge.phpdt.internal.compiler.Compiler; import net.sourceforge.phpdt.internal.compiler.DefaultErrorHandlingPolicies; import net.sourceforge.phpdt.internal.compiler.ICompilerRequestor; import net.sourceforge.phpdt.internal.compiler.IErrorHandlingPolicy; import net.sourceforge.phpdt.internal.compiler.IProblemFactory; import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration; import net.sourceforge.phpdt.internal.compiler.env.INameEnvironment; import net.sourceforge.phpdt.internal.compiler.env.ISourceType; import net.sourceforge.phpdt.internal.compiler.lookup.PackageBinding; import net.sourceforge.phpdt.internal.compiler.parser.SourceTypeConverter; import net.sourceforge.phpdt.internal.compiler.parser.UnitParser; import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation; import net.sourceforge.phpdt.internal.compiler.problem.DefaultProblemFactory; import net.sourceforge.phpdt.internal.core.util.Util; import org.eclipse.core.runtime.IProgressMonitor; /** * Responsible for resolving types inside a compilation unit being reconciled, * reporting the discovered problems to a given IProblemRequestor. */ public class CompilationUnitProblemFinder extends Compiler { /** * Answer a new CompilationUnitVisitor using the given name environment and * compiler options. The environment and options will be in effect for the * lifetime of the compiler. When the compiler is run, compilation results * are sent to the given requestor. * * @param environment * org.eclipse.jdt.internal.compiler.api.env.INameEnvironment * Environment used by the compiler in order to resolve type and * package names. The name environment implements the actual * connection of the compiler to the outside world (e.g. in batch * mode the name environment is performing pure file accesses, * reuse previous build state or connection to repositories). * Note: the name environment is responsible for implementing the * actual classpath rules. * * @param policy * org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy * Configurable part for problem handling, allowing the compiler * client to specify the rules for handling problems (stop on * first error or accumulate them all) and at the same time * perform some actions such as opening a dialog in UI when * compiling interactively. * @see org.eclipse.jdt.internal.compiler.api.problem.DefaultErrorHandlingPolicies * * @param settings * The settings to use for the resolution. * * @param requestor * org.eclipse.jdt.internal.compiler.api.ICompilerRequestor * Component which will receive and persist all compilation * results and is intended to consume them as they are produced. * Typically, in a batch compiler, it is responsible for writing * out the actual .class files to the file system. * @see org.eclipse.jdt.internal.compiler.api.CompilationResult * * @param problemFactory * org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory * Factory used inside the compiler to create problem * descriptors. It allows the compiler client to supply its own * representation of compilation problems in order to avoid * object conversions. Note that the factory is not supposed to * accumulate the created problems, the compiler will gather them * all and hand them back as part of the compilation unit result. */ protected CompilationUnitProblemFinder(INameEnvironment environment, IErrorHandlingPolicy policy, Map settings, ICompilerRequestor requestor, IProblemFactory problemFactory) { super(environment, policy, settings, requestor, problemFactory, true); } /** * Add additional source types */ public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding) { // ensure to jump back to toplevel type for first one (could be a // member) // while (sourceTypes[0].getEnclosingType() != null) // sourceTypes[0] = sourceTypes[0].getEnclosingType(); CompilationResult result = new CompilationResult(sourceTypes[0] .getFileName(), 1, 1, 10); // this.options.maxProblemsPerUnit); // need to hold onto this CompilationUnitDeclaration unit = SourceTypeConverter .buildCompilationUnit(sourceTypes,// sourceTypes[0] is always // toplevel here true, // need field and methods true, // need member types true, // need field initialization lookupEnvironment.problemReporter, result); if (unit != null) { this.lookupEnvironment.buildTypeBindings(unit); this.lookupEnvironment.completeTypeBindings(unit, true); } } /* * Low-level API performing the actual compilation */ protected static IErrorHandlingPolicy getHandlingPolicy() { return DefaultErrorHandlingPolicies.proceedWithAllProblems(); } protected static INameEnvironment getNameEnvironment( ICompilationUnit sourceUnit) throws JavaModelException { return (SearchableEnvironment) ((JavaProject) sourceUnit .getJavaProject()).getSearchableNameEnvironment(); } /* * Answer the component to which will be handed back compilation results * from the compiler */ protected static ICompilerRequestor getRequestor() { return new ICompilerRequestor() { public void acceptResult(CompilationResult compilationResult) { } }; } protected static IProblemFactory getProblemFactory(final char[] fileName, final IProblemRequestor problemRequestor, final IProgressMonitor monitor) { return new DefaultProblemFactory(Locale.getDefault()) { public IProblem createProblem(char[] originatingFileName, int problemId, String[] problemArguments, String[] messageArguments, int severity, int startPosition, int endPosition, int lineNumber) { if (monitor != null && monitor.isCanceled()) { throw new AbortCompilation(true, null); // silent abort } IProblem problem = super.createProblem(originatingFileName, problemId, problemArguments, messageArguments, severity, startPosition, endPosition, lineNumber); // only report local problems if (CharOperation.equals(originatingFileName, fileName)) { if (JavaModelManager.VERBOSE) { System.out .println("PROBLEM FOUND while reconciling : " + problem.getMessage());//$NON-NLS-1$ } problemRequestor.acceptProblem(problem); } if (monitor != null && monitor.isCanceled()) { throw new AbortCompilation(true, null); // silent abort } return problem; } }; } public static CompilationUnitDeclaration process( CompilationUnitDeclaration unit, ICompilationUnit unitElement, char[] contents, UnitParser parser, WorkingCopyOwner workingCopyOwner, IProblemRequestor problemRequestor, IProblemFactory problemFactory, boolean cleanupCU, IProgressMonitor monitor) throws JavaModelException { char[] fileName = unitElement.getElementName().toCharArray(); JavaProject project = (JavaProject) unitElement.getJavaProject(); CompilationUnitProblemFinder problemFinder = new CompilationUnitProblemFinder( project.newSearchableNameEnvironment(workingCopyOwner), getHandlingPolicy(), project.getOptions(true), getRequestor(), problemFactory); if (parser != null) { problemFinder.parser = parser; } try { IPackageFragment packageFragment = (IPackageFragment) unitElement .getAncestor(IJavaElement.PACKAGE_FRAGMENT); char[][] expectedPackageName = null; if (packageFragment != null) { expectedPackageName = CharOperation.splitOn('.', packageFragment.getElementName().toCharArray()); } if (unit == null) { unit = problemFinder.resolve( new BasicCompilationUnit(contents, expectedPackageName, new String(fileName), unitElement), true, // verify // methods true); // , // analyze code // true); // generate code } else { problemFinder.resolve(unit, null, // no need for source true, // verify methods true); // , // analyze code // true); // generate code } reportProblems(unit, problemRequestor, monitor); return unit; } catch (RuntimeException e) { // avoid breaking other tools due to internal compiler failure // (40334) Util.log(e, "Exception occurred during problem detection: "); //$NON-NLS-1$ throw new JavaModelException(e, IJavaModelStatusConstants.COMPILER_FAILURE); } finally { if (cleanupCU && unit != null) { unit.cleanUp(); } problemFinder.lookupEnvironment.reset(); } } public static CompilationUnitDeclaration process( ICompilationUnit unitElement, char[] contents, WorkingCopyOwner workingCopyOwner, IProblemRequestor problemRequestor, boolean cleanupCU, IProgressMonitor monitor) throws JavaModelException { return process(null/* no CompilationUnitDeclaration */, unitElement, contents, null/* use default Parser */, workingCopyOwner, problemRequestor, new DefaultProblemFactory(), cleanupCU, monitor); } public static CompilationUnitDeclaration process( ICompilationUnit unitElement, IProblemRequestor problemRequestor, IProgressMonitor monitor) throws JavaModelException { char[] fileName = unitElement.getElementName().toCharArray(); IJavaProject project = unitElement.getJavaProject(); CompilationUnitProblemFinder problemFinder = new CompilationUnitProblemFinder( getNameEnvironment(unitElement), getHandlingPolicy(), project .getOptions(true), getRequestor(), getProblemFactory( fileName, problemRequestor, monitor)); CompilationUnitDeclaration unit = null; try { String encoding = project.getOption(JavaCore.CORE_ENCODING, true); IPackageFragment packageFragment = (IPackageFragment) unitElement .getAncestor(IJavaElement.PACKAGE_FRAGMENT); char[][] expectedPackageName = null; if (packageFragment != null) { expectedPackageName = CharOperation.splitOn('.', packageFragment.getElementName().toCharArray()); } unit = problemFinder.resolve(new BasicCompilationUnit(unitElement .getSource().toCharArray(), expectedPackageName, new String(fileName), encoding), true, // verify methods true); // analyze code // true); // generate code return unit; } finally { if (unit != null) { unit.cleanUp(); } problemFinder.lookupEnvironment.reset(); } } private static void reportProblems(CompilationUnitDeclaration unit, IProblemRequestor problemRequestor, IProgressMonitor monitor) { CompilationResult unitResult = unit.compilationResult; IProblem[] problems = unitResult.getAllProblems(); for (int i = 0, problemLength = problems == null ? 0 : problems.length; i < problemLength; i++) { if (JavaModelManager.VERBOSE) { System.out .println("PROBLEM FOUND while reconciling : " + problems[i].getMessage());//$NON-NLS-1$ } if (monitor != null && monitor.isCanceled()) break; problemRequestor.acceptProblem(problems[i]); } } }