| /******************************************************************************* |
| * Copyright (c) 2000, 2011 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.core; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.jdt.core.*; |
| import org.eclipse.jdt.core.compiler.CategorizedProblem; |
| import org.eclipse.jdt.internal.compiler.*; |
| import org.eclipse.jdt.internal.compiler.Compiler; |
| import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; |
| import org.eclipse.jdt.internal.compiler.env.AccessRestriction; |
| import org.eclipse.jdt.internal.compiler.env.INameEnvironment; |
| import org.eclipse.jdt.internal.compiler.env.ISourceType; |
| import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
| import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; |
| import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter; |
| import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; |
| import org.eclipse.jdt.internal.core.util.CommentRecorderParser; |
| import org.eclipse.jdt.internal.core.util.Util; |
| |
| /** |
| * 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.DefaultErrorHandlingPolicies |
| * |
| * @param compilerOptions The compiler options 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.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, |
| CompilerOptions compilerOptions, |
| ICompilerRequestor requestor, |
| IProblemFactory problemFactory) { |
| |
| super(environment, |
| policy, |
| compilerOptions, |
| requestor, |
| problemFactory |
| ); |
| } |
| |
| /** |
| * Add additional source types |
| */ |
| public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) { |
| // 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, this.options.maxProblemsPerUnit); |
| |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=305259, build the compilation unit in its own sand box. |
| final long savedComplianceLevel = this.options.complianceLevel; |
| final long savedSourceLevel = this.options.sourceLevel; |
| |
| try { |
| IJavaProject project = ((SourceTypeElementInfo) sourceTypes[0]).getHandle().getJavaProject(); |
| this.options.complianceLevel = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_COMPLIANCE, true)); |
| this.options.sourceLevel = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_SOURCE, true)); |
| |
| // need to hold onto this |
| CompilationUnitDeclaration unit = |
| SourceTypeConverter.buildCompilationUnit( |
| sourceTypes,//sourceTypes[0] is always toplevel here |
| SourceTypeConverter.FIELD_AND_METHOD // need field and methods |
| | SourceTypeConverter.MEMBER_TYPE // need member types |
| | SourceTypeConverter.FIELD_INITIALIZATION, // need field initialization |
| this.lookupEnvironment.problemReporter, |
| result); |
| |
| if (unit != null) { |
| this.lookupEnvironment.buildTypeBindings(unit, accessRestriction); |
| this.lookupEnvironment.completeTypeBindings(unit); |
| } |
| } finally { |
| this.options.complianceLevel = savedComplianceLevel; |
| this.options.sourceLevel = savedSourceLevel; |
| } |
| } |
| |
| protected static CompilerOptions getCompilerOptions(Map settings, boolean creatingAST, boolean statementsRecovery) { |
| CompilerOptions compilerOptions = new CompilerOptions(settings); |
| compilerOptions.performMethodsFullRecovery = statementsRecovery; |
| compilerOptions.performStatementsRecovery = statementsRecovery; |
| compilerOptions.parseLiteralExpressionsAsConstants = !creatingAST; /*parse literal expressions as constants only if not creating a DOM AST*/ |
| compilerOptions.storeAnnotations = creatingAST; /*store annotations in the bindings if creating a DOM AST*/ |
| return compilerOptions; |
| } |
| |
| /* |
| * Low-level API performing the actual compilation |
| */ |
| protected static IErrorHandlingPolicy getHandlingPolicy() { |
| return DefaultErrorHandlingPolicies.proceedWithAllProblems(); |
| } |
| |
| /* |
| * 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) { |
| // default requestor doesn't handle compilation results back |
| } |
| }; |
| } |
| |
| /* |
| * Can return null if the process was aborted or canceled |
| */ |
| public static CompilationUnitDeclaration process( |
| CompilationUnit unitElement, |
| SourceElementParser parser, |
| WorkingCopyOwner workingCopyOwner, |
| HashMap problems, |
| boolean creatingAST, |
| int reconcileFlags, |
| IProgressMonitor monitor) |
| throws JavaModelException { |
| |
| JavaProject project = (JavaProject) unitElement.getJavaProject(); |
| CancelableNameEnvironment environment = null; |
| CancelableProblemFactory problemFactory = null; |
| CompilationUnitProblemFinder problemFinder = null; |
| CompilationUnitDeclaration unit = null; |
| try { |
| environment = new CancelableNameEnvironment(project, workingCopyOwner, monitor); |
| problemFactory = new CancelableProblemFactory(monitor); |
| CompilerOptions compilerOptions = getCompilerOptions(project.getOptions(true), creatingAST, ((reconcileFlags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0)); |
| boolean ignoreMethodBodies = (reconcileFlags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; |
| compilerOptions.ignoreMethodBodies = ignoreMethodBodies; |
| problemFinder = new CompilationUnitProblemFinder( |
| environment, |
| getHandlingPolicy(), |
| compilerOptions, |
| getRequestor(), |
| problemFactory); |
| boolean analyzeAndGenerateCode = true; |
| if (ignoreMethodBodies) { |
| analyzeAndGenerateCode = false; |
| } |
| try { |
| if (parser != null) { |
| problemFinder.parser = parser; |
| unit = parser.parseCompilationUnit(unitElement, true/*full parse*/, monitor); |
| problemFinder.resolve( |
| unit, |
| unitElement, |
| true, // verify methods |
| analyzeAndGenerateCode, // analyze code |
| analyzeAndGenerateCode); // generate code |
| } else { |
| unit = |
| problemFinder.resolve( |
| unitElement, |
| true, // verify methods |
| analyzeAndGenerateCode, // analyze code |
| analyzeAndGenerateCode); // generate code |
| } |
| } catch (AbortCompilation e) { |
| problemFinder.handleInternalException(e, unit); |
| } |
| if (unit != null) { |
| CompilationResult unitResult = unit.compilationResult; |
| CategorizedProblem[] unitProblems = unitResult.getProblems(); |
| int length = unitProblems == null ? 0 : unitProblems.length; |
| if (length > 0) { |
| CategorizedProblem[] categorizedProblems = new CategorizedProblem[length]; |
| System.arraycopy(unitProblems, 0, categorizedProblems, 0, length); |
| problems.put(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, categorizedProblems); |
| } |
| unitProblems = unitResult.getTasks(); |
| length = unitProblems == null ? 0 : unitProblems.length; |
| if (length > 0) { |
| CategorizedProblem[] categorizedProblems = new CategorizedProblem[length]; |
| System.arraycopy(unitProblems, 0, categorizedProblems, 0, length); |
| problems.put(IJavaModelMarker.TASK_MARKER, categorizedProblems); |
| } |
| if (NameLookup.VERBOSE) { |
| System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ |
| System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| } catch (OperationCanceledException e) { |
| // catch this exception so as to not enter the catch(RuntimeException e) below |
| throw e; |
| } catch(RuntimeException e) { |
| // avoid breaking other tools due to internal compiler failure (40334) |
| String lineDelimiter = unitElement.findRecommendedLineSeparator(); |
| StringBuffer message = new StringBuffer("Exception occurred during problem detection:"); //$NON-NLS-1$ |
| message.append(lineDelimiter); |
| message.append("----------------------------------- SOURCE BEGIN -------------------------------------"); //$NON-NLS-1$ |
| message.append(lineDelimiter); |
| message.append(unitElement.getSource()); |
| message.append(lineDelimiter); |
| message.append("----------------------------------- SOURCE END -------------------------------------"); //$NON-NLS-1$ |
| Util.log(e, message.toString()); |
| throw new JavaModelException(e, IJavaModelStatusConstants.COMPILER_FAILURE); |
| } finally { |
| if (environment != null) |
| environment.setMonitor(null); // don't hold a reference to this external object |
| if (problemFactory != null) |
| problemFactory.monitor = null; // don't hold a reference to this external object |
| // NB: unit.cleanUp() is done by caller |
| if (problemFinder != null && !creatingAST) |
| problemFinder.lookupEnvironment.reset(); |
| } |
| return unit; |
| } |
| |
| public static CompilationUnitDeclaration process( |
| CompilationUnit unitElement, |
| WorkingCopyOwner workingCopyOwner, |
| HashMap problems, |
| boolean creatingAST, |
| int reconcileFlags, |
| IProgressMonitor monitor) |
| throws JavaModelException { |
| |
| return process(unitElement, null/*use default Parser*/, workingCopyOwner, problems, creatingAST, reconcileFlags, monitor); |
| } |
| |
| /* (non-Javadoc) |
| * Fix for bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=60689. |
| * @see org.eclipse.jdt.internal.compiler.Compiler#initializeParser() |
| */ |
| public void initializeParser() { |
| this.parser = new CommentRecorderParser(this.problemReporter, this.options.parseLiteralExpressionsAsConstants); |
| } |
| } |
| |