org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ecj Show documentation
Show all versions of ecj Show documentation
Eclipse Compiler for Java(TM)
/*******************************************************************************
* 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.eclipse.jdt.internal.compiler.lookup;
import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching;
import 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.parameterNonNullness = originalMethod.parameterNonNullness;
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: 'Class extends raw(X)>
*/
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.createAnnotatedType(rawType, new AnnotationBinding[] { environment.getNonNullAnnotation() });
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.createAnnotatedType(method.returnType, new AnnotationBinding[] { environment.getNonNullAnnotation() });
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;
}
}