All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aspectj.org.eclipse.jdt.internal.core.CompilationUnitProblemFinder Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2000, 2021 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.core;

import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.aspectj.org.eclipse.jdt.core.*;
import org.aspectj.org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.aspectj.org.eclipse.jdt.internal.compiler.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.Compiler;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.IModule;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.ISourceType;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
import org.aspectj.org.eclipse.jdt.internal.core.util.CommentRecorderParser;
import org.aspectj.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.
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
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
	 */
	@Override
	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;

		LookupEnvironment environment = packageBinding.environment;
		if (environment == null)
			environment = this.lookupEnvironment;

		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
						environment.problemReporter,
						result);

			if (unit != null) {
				environment.buildTypeBindings(unit, accessRestriction);
				CompilationUnitDeclaration previousUnitBeingCompleted = this.lookupEnvironment.unitBeingCompleted;
				environment.completeTypeBindings(unit);
				this.lookupEnvironment.unitBeingCompleted = previousUnitBeingCompleted;
			}
		} finally {
			this.options.complianceLevel = savedComplianceLevel;
			this.options.sourceLevel = savedSourceLevel;
		}
	}

	@Override
	public void accept(IModule module, LookupEnvironment environment) {
		IModuleDescription handle = null;
		if (module instanceof ModuleDescriptionInfo) {
			handle = ((ModuleDescriptionInfo) module).getHandle();
		}
		if (handle == null) {
			super.accept(module, environment);
			return;
		}
		CompilationResult result =
				new CompilationResult(TypeConstants.MODULE_INFO_FILE_NAME, 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;

		if (environment == null)
			environment = this.lookupEnvironment;

		try {
			IJavaProject project = handle.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.buildModularCompilationUnit(
						module,
						environment.problemReporter,
						result);

			if (unit != null) {
				environment.buildTypeBindings(unit, null);
				environment.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*/
		if (creatingAST)
			compilerOptions.storeAnnotations = true; /* 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() {
			@Override
			public void acceptResult(CompilationResult compilationResult) {
				// default requestor doesn't handle compilation results back
			}
		};
	}

	private static boolean isTestSource(IJavaProject project, ICompilationUnit cu) {
		try {
			IClasspathEntry[] resolvedClasspath = project.getResolvedClasspath(true);
			final IPath resourcePath = cu.getResource().getFullPath();
			for (IClasspathEntry e : resolvedClasspath) {
				if (e.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
					if (e.isTest()) {
						if (e.getPath().isPrefixOf(resourcePath)) {
							return true;
						}
					}
				}
			}
		} catch (JavaModelException e) {
			Util.log(e, "Exception while determining if compilation unit \"" + cu.getElementName() //$NON-NLS-1$
					+ "\" is test source"); //$NON-NLS-1$
		}
		return false;
	}

	/*
	 * 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 = unitElement.getJavaProject();
		CancelableNameEnvironment environment = null;
		CancelableProblemFactory problemFactory = null;
		CompilationUnitProblemFinder problemFinder = null;
		CompilationUnitDeclaration unit = null;
		try {
			environment = new CancelableNameEnvironment(project, workingCopyOwner, monitor, !isTestSource(unitElement.getJavaProject(), unitElement));
			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.getCUProblems();
				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();
			StringBuilder message = new StringBuilder("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()
	 */
	@Override
	public void initializeParser() {
		this.parser = new CommentRecorderParser(this.problemReporter, this.options.parseLiteralExpressionsAsConstants);
	}
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy