| /******************************************************************************* |
| * Copyright (c) 2000, 2018 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 - Contribution for |
| * bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files |
| * Bug 416174 - [1.8][compiler][null] Bogus name clash error with null annotations |
| * Bug 416176 - [1.8][compiler][null] null type annotations cause grief on type variables |
| * Bug 423504 - [1.8] Implement "18.5.3 Functional Interface Parameterization Inference" |
| * Bug 425783 - An internal error occurred during: "Requesting Java AST from selection". java.lang.StackOverflowError |
| * Bug 438458 - [1.8][null] clean up handling of null type annotations wrt type variables |
| * Bug 441693 - [1.8][null] Bogus warning for type argument annotated with @NonNull |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.compiler.lookup; |
| |
| import java.util.Set; |
| |
| import org.eclipse.jdt.core.compiler.CharOperation; |
| |
| /** |
| * Denote a raw type, i.e. a generic type referenced without any type arguments. |
| * e.g. X<T extends Exception> can be used a raw type 'X', in which case it |
| * will behave as X<Exception> |
| */ |
| public class RawTypeBinding extends ParameterizedTypeBinding { |
| |
| /** |
| * Raw type arguments are erasure of respective parameter bounds. But we may not have resolved |
| * these bounds yet if creating raw types while supertype hierarchies are being connected. |
| * Therefore, use 'null' instead, and access these in a lazy way later on (when substituting). |
| */ |
| public RawTypeBinding(ReferenceBinding type, ReferenceBinding enclosingType, LookupEnvironment environment){ |
| super(type, null, enclosingType, environment); |
| this.tagBits &= ~TagBits.HasMissingType; |
| if ((type.tagBits & TagBits.HasMissingType) != 0) { |
| if (type instanceof MissingTypeBinding) { |
| this.tagBits |= TagBits.HasMissingType; |
| } else if (type instanceof ParameterizedTypeBinding) { |
| ParameterizedTypeBinding parameterizedTypeBinding = (ParameterizedTypeBinding) type; |
| if (parameterizedTypeBinding.genericType() instanceof MissingTypeBinding) { |
| this.tagBits |= TagBits.HasMissingType; |
| } |
| } |
| } |
| if (enclosingType != null && (enclosingType.tagBits & TagBits.HasMissingType) != 0) { |
| if (enclosingType instanceof MissingTypeBinding) { |
| this.tagBits |= TagBits.HasMissingType; |
| } else if (enclosingType instanceof ParameterizedTypeBinding) { |
| ParameterizedTypeBinding parameterizedTypeBinding = (ParameterizedTypeBinding) enclosingType; |
| if (parameterizedTypeBinding.genericType() instanceof MissingTypeBinding) { |
| this.tagBits |= TagBits.HasMissingType; |
| } |
| } |
| } |
| if (enclosingType == null || !this.hasEnclosingInstanceContext() || (enclosingType.modifiers & ExtraCompilerModifiers.AccGenericSignature) == 0) { |
| this.modifiers &= ~ExtraCompilerModifiers.AccGenericSignature; // only need signature if enclosing needs one |
| } |
| } |
| |
| @Override |
| public char[] computeUniqueKey(boolean isLeaf) { |
| StringBuffer sig = new StringBuffer(10); |
| if (isMemberType() && (enclosingType().isParameterizedType() || enclosingType().isRawType())) { |
| if (!hasEnclosingInstanceContext()) { |
| char[] typeSig = enclosingType().signature(); // don't consider generics from enclosing of static member |
| sig.append(typeSig, 0, typeSig.length-1); // copy all but trailing semicolon |
| sig.append('$'); // for consistency with keys prior to https://bugs.eclipse.org/460491 |
| } else { |
| char[] typeSig = enclosingType().computeUniqueKey(false/*not a leaf*/); |
| sig.append(typeSig, 0, typeSig.length-1); // copy all but trailing semicolon |
| sig.append('.'); |
| } |
| sig.append(sourceName()); |
| if (genericType().typeVariables() != Binding.NO_TYPE_VARIABLES) // don't show <> if raw only due to a generic enclosing |
| sig.append('<').append('>'); |
| sig.append(';'); |
| } else { |
| sig.append(genericType().computeUniqueKey(false/*not a leaf*/)); |
| sig.insert(sig.length()-1, "<>"); //$NON-NLS-1$ |
| } |
| |
| int sigLength = sig.length(); |
| char[] uniqueKey = new char[sigLength]; |
| sig.getChars(0, sigLength, uniqueKey, 0); |
| return uniqueKey; |
| } |
| |
| @Override |
| public TypeBinding clone(TypeBinding outerType) { |
| return new RawTypeBinding(this.actualType(), (ReferenceBinding) outerType, this.environment); |
| } |
| |
| @Override |
| public TypeBinding withoutToplevelNullAnnotation() { |
| if (!hasNullTypeAnnotations()) |
| return this; |
| ReferenceBinding unannotatedGenericType = (ReferenceBinding) this.environment.getUnannotatedType(this.genericType()); |
| AnnotationBinding[] newAnnotations = this.environment.filterNullTypeAnnotations(this.typeAnnotations); |
| return this.environment.createRawType(unannotatedGenericType, this.enclosingType(), newAnnotations); |
| } |
| |
| /** |
| * @see org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding#createParameterizedMethod(org.eclipse.jdt.internal.compiler.lookup.MethodBinding) |
| */ |
| @Override |
| public ParameterizedMethodBinding createParameterizedMethod(MethodBinding originalMethod) { |
| if (originalMethod.typeVariables == Binding.NO_TYPE_VARIABLES || originalMethod.isStatic()) { |
| return super.createParameterizedMethod(originalMethod); |
| } |
| return this.environment.createParameterizedGenericMethod(originalMethod, this); |
| } |
| |
| @Override |
| public boolean isParameterizedType() { |
| return false; |
| } |
| |
| @Override |
| public int kind() { |
| return RAW_TYPE; |
| } |
| |
| /** |
| * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#debugName() |
| */ |
| @Override |
| public String debugName() { |
| if (this.hasTypeAnnotations()) |
| return annotatedDebugName(); |
| StringBuffer nameBuffer = new StringBuffer(10); |
| nameBuffer.append(actualType().sourceName()).append("#RAW"); //$NON-NLS-1$ |
| return nameBuffer.toString(); |
| } |
| @Override |
| public String annotatedDebugName() { |
| StringBuffer buffer = new StringBuffer(super.annotatedDebugName()); |
| buffer.append("#RAW"); //$NON-NLS-1$ |
| return buffer.toString(); |
| } |
| /** |
| * Ltype<param1 ... paramN>; |
| * LY<TT;>; |
| */ |
| @Override |
| public char[] genericTypeSignature() { |
| if (this.genericTypeSignature == null) { |
| if ((this.modifiers & ExtraCompilerModifiers.AccGenericSignature) == 0) { |
| this.genericTypeSignature = genericType().signature(); |
| } else { |
| StringBuffer sig = new StringBuffer(10); |
| if (isMemberType() && hasEnclosingInstanceContext()) { |
| ReferenceBinding enclosing = enclosingType(); |
| char[] typeSig = enclosing.genericTypeSignature(); |
| sig.append(typeSig, 0, typeSig.length-1);// copy all but trailing semicolon |
| if ((enclosing.modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0) { |
| sig.append('.'); |
| } else { |
| sig.append('$'); |
| } |
| sig.append(sourceName()); |
| } else { |
| char[] typeSig = genericType().signature(); |
| sig.append(typeSig, 0, typeSig.length-1);// copy all but trailing semicolon |
| } |
| sig.append(';'); |
| int sigLength = sig.length(); |
| this.genericTypeSignature = new char[sigLength]; |
| sig.getChars(0, sigLength, this.genericTypeSignature, 0); |
| } |
| } |
| return this.genericTypeSignature; |
| } |
| |
| @Override |
| public boolean isEquivalentTo(TypeBinding otherType) { |
| if (equalsEquals(this, otherType) || equalsEquals(erasure(), otherType)) |
| return true; |
| if (otherType == null) |
| return false; |
| switch(otherType.kind()) { |
| |
| case Binding.WILDCARD_TYPE : |
| case Binding.INTERSECTION_TYPE: |
| return ((WildcardBinding) otherType).boundCheck(this); |
| |
| case Binding.GENERIC_TYPE : |
| case Binding.PARAMETERIZED_TYPE : |
| case Binding.RAW_TYPE : |
| return TypeBinding.equalsEquals(erasure(), otherType.erasure()); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean isProvablyDistinct(TypeBinding otherType) { |
| if (TypeBinding.equalsEquals(this, otherType) || TypeBinding.equalsEquals(erasure(), otherType)) // https://bugs.eclipse.org/bugs/show_bug.cgi?id=329588 |
| return false; |
| if (otherType == null) |
| return true; |
| switch(otherType.kind()) { |
| |
| case Binding.GENERIC_TYPE : |
| case Binding.PARAMETERIZED_TYPE : |
| case Binding.RAW_TYPE : |
| return TypeBinding.notEquals(erasure(), otherType.erasure()); |
| } |
| return true; |
| } |
| @Override |
| public boolean isSubtypeOf(TypeBinding right, boolean simulatingBugJDK8026527) { |
| if (simulatingBugJDK8026527) { |
| right = this.environment.convertToRawType(right.erasure(), false); |
| } |
| return super.isSubtypeOf(right, simulatingBugJDK8026527); |
| } |
| |
| @Override |
| public boolean isProperType(boolean admitCapture18) { |
| TypeBinding actualType = actualType(); |
| return actualType != null && actualType.isProperType(admitCapture18); |
| } |
| |
| @Override |
| protected void initializeArguments() { |
| TypeVariableBinding[] typeVariables = genericType().typeVariables(); |
| int length = typeVariables.length; |
| TypeBinding[] typeArguments = new TypeBinding[length]; |
| for (int i = 0; i < length; i++) { |
| // perform raw conversion on variable upper bound - could cause infinite regression if arguments were initialized lazily |
| typeArguments[i] = this.environment.convertToRawType(typeVariables[i].erasure(), false /*do not force conversion of enclosing types*/); |
| } |
| this.arguments = typeArguments; |
| } |
| |
| @Override |
| public ParameterizedTypeBinding capture(Scope scope, int start, int end) { |
| return this; |
| } |
| |
| @Override |
| public TypeBinding uncapture(Scope scope) { |
| return this; |
| } |
| |
| @Override |
| //{ObjectTeams: |
| protected |
| // SH} |
| TypeBinding substituteInferenceVariable(InferenceVariable var, TypeBinding substituteType) { |
| // NEVER substitute the type arguments of a raw type |
| return this; |
| } |
| |
| @Override |
| public MethodBinding getSingleAbstractMethod(Scope scope, boolean replaceWildcards) { |
| int index = replaceWildcards ? 0 : 1; |
| if (this.singleAbstractMethod != null) { |
| if (this.singleAbstractMethod[index] != null) |
| return this.singleAbstractMethod[index]; |
| } else { |
| this.singleAbstractMethod = new MethodBinding[2]; |
| } |
| final ReferenceBinding genericType = genericType(); |
| MethodBinding theAbstractMethod = genericType.getSingleAbstractMethod(scope, replaceWildcards); |
| if (theAbstractMethod == null || !theAbstractMethod.isValidBinding()) |
| return this.singleAbstractMethod[index] = theAbstractMethod; |
| |
| ReferenceBinding declaringType = (ReferenceBinding) scope.environment().convertToRawType(genericType, true); |
| declaringType = (ReferenceBinding) declaringType.findSuperTypeOriginatingFrom(theAbstractMethod.declaringClass); |
| MethodBinding [] choices = declaringType.getMethods(theAbstractMethod.selector); |
| for (int i = 0, length = choices.length; i < length; i++) { |
| MethodBinding method = choices[i]; |
| if (!method.isAbstract() || method.redeclaresPublicObjectMethod(scope)) continue; // (re)skip statics, defaults, public object methods ... |
| this.singleAbstractMethod[index] = method; |
| break; |
| } |
| return this.singleAbstractMethod[index]; |
| } |
| @Override |
| public boolean mentionsAny(TypeBinding[] parameters, int idx) { |
| return false; |
| } |
| /** |
| * @see org.eclipse.jdt.internal.compiler.lookup.Binding#readableName() |
| */ |
| @Override |
| public char[] readableName(boolean showGenerics) /*java.lang.Object, p.X<T> */ { |
| char[] readableName; |
| if (isMemberType()) { |
| readableName = CharOperation.concat(enclosingType().readableName(showGenerics && hasEnclosingInstanceContext()), this.sourceName, '.'); |
| } else { |
| readableName = CharOperation.concatWith(actualType().compoundName, '.'); |
| } |
| return readableName; |
| } |
| |
| /** |
| * @see org.eclipse.jdt.internal.compiler.lookup.Binding#shortReadableName() |
| */ |
| @Override |
| public char[] shortReadableName(boolean showGenerics) /*Object*/ { |
| char[] shortReadableName; |
| if (isMemberType()) { |
| shortReadableName = CharOperation.concat(enclosingType().shortReadableName(showGenerics && hasEnclosingInstanceContext()), this.sourceName, '.'); |
| } else { |
| shortReadableName = actualType().sourceName; |
| } |
| return shortReadableName; |
| } |
| |
| //{ObjectTeams: |
| @Override |
| protected |
| // SH} |
| void collectInferenceVariables(Set<InferenceVariable> variables) { |
| // nothing to collect for a raw type. |
| } |
| |
| @Override |
| public ReferenceBinding upwardsProjection(Scope scope, TypeBinding[] mentionedTypeVariables) { |
| return this; |
| } |
| |
| @Override |
| public ReferenceBinding downwardsProjection(Scope scope, TypeBinding[] mentionedTypeVariables) { |
| return this; |
| } |
| } |