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

org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding 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
// ASPECTJ
/*******************************************************************************
 * Copyright (c) 2000, 2017 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
 *     Stephan Herrmann - Contributions for
 *								bug 186342 - [compiler][null] Using annotations for null checking
 *								bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
 *								bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files
 *								Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099
 *								Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings.
 *								Bug 425152 - [1.8] [compiler] Lambda Expression not resolved but flow analyzed leading to NPE.
 *								Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
 *******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.compiler.lookup;

import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Wildcard;

/**
 * Binding denoting a method after type parameter substitutions got performed.
 * On parameterized type bindings, all methods got substituted, regardless whether
 * their signature did involve generics or not, so as to get the proper declaringClass for
 * these methods.
 */
public class ParameterizedMethodBinding extends MethodBinding {

	protected MethodBinding originalMethod;

	/**
	 * Create method of parameterized type, substituting original parameters/exception/return type with type arguments.
	 */
	public ParameterizedMethodBinding(final ParameterizedTypeBinding parameterizedDeclaringClass, MethodBinding originalMethod) {
		super(
				originalMethod.modifiers,
				originalMethod.selector,
				originalMethod.returnType,
				originalMethod.parameters,
				originalMethod.thrownExceptions,
				parameterizedDeclaringClass);
		this.originalMethod = originalMethod;
		/* missing type bit cannot be copied as is it might come from the return type or a parameter type that
		 * is substituted by a raw type.
		 */
		this.tagBits = originalMethod.tagBits & ~TagBits.HasMissingType;
		this.parameterFlowBits = originalMethod.parameterFlowBits;
		this.defaultNullness = originalMethod.defaultNullness;

		final TypeVariableBinding[] originalVariables = originalMethod.typeVariables;
		Substitution substitution = null;
		final int length = originalVariables.length;
		final boolean isStatic = originalMethod.isStatic();
		if (length == 0) {
			this.typeVariables = Binding.NO_TYPE_VARIABLES;
			if (!isStatic) substitution = parameterizedDeclaringClass;
		} else {
			// at least fix up the declaringElement binding + bound substitution if non static
			final TypeVariableBinding[] substitutedVariables = new TypeVariableBinding[length];
			for (int i = 0; i < length; i++) { // copy original type variable to relocate
				TypeVariableBinding originalVariable = originalVariables[i];
				substitutedVariables[i] = new TypeVariableBinding(originalVariable.sourceName, this, originalVariable.rank, parameterizedDeclaringClass.environment);
				substitutedVariables[i].tagBits |= (originalVariable.tagBits & (TagBits.AnnotationNullMASK|TagBits.HasNullTypeAnnotation));
			}
			this.typeVariables = substitutedVariables;

			// need to substitute old var refs with new ones (double substitution: declaringClass + new type variables)
			substitution = new Substitution() {
				@Override
				public LookupEnvironment environment() {
					return parameterizedDeclaringClass.environment;
				}
				@Override
				public boolean isRawSubstitution() {
					return !isStatic && parameterizedDeclaringClass.isRawSubstitution();
				}
				@Override
				public TypeBinding substitute(TypeVariableBinding typeVariable) {
					// check this variable can be substituted given copied variables
					if (typeVariable.rank < length && TypeBinding.equalsEquals(originalVariables[typeVariable.rank], typeVariable)) {
						TypeBinding substitute = substitutedVariables[typeVariable.rank];
						return typeVariable.hasTypeAnnotations() ? environment().createAnnotatedType(substitute, typeVariable.getTypeAnnotations()) : substitute;
					}
					if (!isStatic)
						return parameterizedDeclaringClass.substitute(typeVariable);
					return typeVariable;
				}
			};

			// initialize new variable bounds
			for (int i = 0; i < length; i++) {
				TypeVariableBinding originalVariable = originalVariables[i];
				TypeVariableBinding substitutedVariable = substitutedVariables[i];
				TypeBinding substitutedSuperclass = Scope.substitute(substitution, originalVariable.superclass);
				ReferenceBinding[] substitutedInterfaces = Scope.substitute(substitution, originalVariable.superInterfaces);
				if (originalVariable.firstBound != null) {
					TypeBinding firstBound;
					firstBound = TypeBinding.equalsEquals(originalVariable.firstBound, originalVariable.superclass)
						? substitutedSuperclass // could be array type or interface
						: substitutedInterfaces[0];
					substitutedVariable.setFirstBound(firstBound);
				}
				switch (substitutedSuperclass.kind()) {
					case Binding.ARRAY_TYPE :
						substitutedVariable.setSuperClass(parameterizedDeclaringClass.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_OBJECT, null));
						substitutedVariable.setSuperInterfaces(substitutedInterfaces);
						break;
					default:
						if (substitutedSuperclass.isInterface()) {
							substitutedVariable.setSuperClass(parameterizedDeclaringClass.environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null));
							int interfaceCount = substitutedInterfaces.length;
							System.arraycopy(substitutedInterfaces, 0, substitutedInterfaces = new ReferenceBinding[interfaceCount+1], 1, interfaceCount);
							substitutedInterfaces[0] = (ReferenceBinding) substitutedSuperclass;
							substitutedVariable.setSuperInterfaces(substitutedInterfaces);
						} else {
							substitutedVariable.setSuperClass((ReferenceBinding) substitutedSuperclass); // typeVar was extending other typeVar which got substituted with interface
							substitutedVariable.setSuperInterfaces(substitutedInterfaces);
						}
				}
			}
		}
		if (substitution != null) {
			this.returnType = Scope.substitute(substitution, this.returnType);
			this.parameters = Scope.substitute(substitution, this.parameters);
			this.thrownExceptions = Scope.substitute(substitution, this.thrownExceptions);
			// error case where exception type variable would have been substituted by a non-reference type (207573)
			if (this.thrownExceptions == null) this.thrownExceptions = Binding.NO_EXCEPTIONS;

			// after substitution transfer nullness information from type annotations:
			if (parameterizedDeclaringClass.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) {
				long returnNullBits = NullAnnotationMatching.validNullTagBits(this.returnType.tagBits);
				if (returnNullBits != 0L) {
					this.tagBits &= ~TagBits.AnnotationNullMASK;
					this.tagBits |= returnNullBits;
				}
				int parametersLen = this.parameters.length;
				for (int i=0; i'} into: {@code 'Class}
	 */
	public static ParameterizedMethodBinding instantiateGetClass(TypeBinding receiverType, MethodBinding originalMethod, Scope scope) {
		ParameterizedMethodBinding method = new ParameterizedMethodBinding();
		method.modifiers = originalMethod.modifiers;
		method.selector = originalMethod.selector;
		method.declaringClass = originalMethod.declaringClass;
		method.typeVariables = Binding.NO_TYPE_VARIABLES;
		method.originalMethod = originalMethod;
		method.parameters = originalMethod.parameters;
		method.thrownExceptions = originalMethod.thrownExceptions;
		method.tagBits = originalMethod.tagBits;
		ReferenceBinding genericClassType = scope.getJavaLangClass();
		LookupEnvironment environment = scope.environment();
		TypeBinding rawType = environment.convertToRawType(receiverType.erasure(), false /*do not force conversion of enclosing types*/);
		if (environment.usesNullTypeAnnotations())
			rawType = environment.createNonNullAnnotatedType(rawType);
		method.returnType = environment.createParameterizedType(
			genericClassType,
			new TypeBinding[] {  environment.createWildcard(genericClassType, 0, rawType, null /*no extra bound*/, Wildcard.EXTENDS) },
			null);
		if (environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) {
			if (environment.usesNullTypeAnnotations())
				method.returnType = environment.createNonNullAnnotatedType(method.returnType);
			else
				method.tagBits |= TagBits.AnnotationNonNull;
		}
		if ((method.returnType.tagBits & TagBits.HasMissingType) != 0) {
			method.tagBits |=  TagBits.HasMissingType;
		}
		return method;
	}

	/**
	 * Returns true if some parameters got substituted.
	 */
	@Override
	public boolean hasSubstitutedParameters() {
		return this.parameters != this.originalMethod.parameters;
	}

	/**
	 * Returns true if the return type got substituted.
	 */
	@Override
	public boolean hasSubstitutedReturnType() {
		return this.returnType != this.originalMethod.returnType; //$IDENTITY-COMPARISON$
	}

	/**
	 * Returns the original method (as opposed to parameterized instances)
	 */
	@Override
	public MethodBinding original() {
		return this.originalMethod.original();
	}


	@Override
	public MethodBinding shallowOriginal() {
		return this.originalMethod;
	}
	
	// AspectJ Extension - delegate to the original method
	
	@Override
	public boolean alwaysNeedsAccessMethod() {
		return originalMethod.alwaysNeedsAccessMethod();
	}

	@Override
	public boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invocationSite, Scope scope) {
		if (alwaysNeedsAccessMethod()) return originalMethod.canBeSeenBy(receiverType,invocationSite,scope);
		else                           return super.canBeSeenBy(receiverType,invocationSite,scope);
	}

	@Override
	public MethodBinding getAccessMethod(boolean staticReference) {
		return originalMethod.getAccessMethod(staticReference);
	}
	
	@Override
	public AbstractMethodDeclaration sourceMethod() {
		return originalMethod.sourceMethod();
	}
	
	// End AspectJ Extension
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy