| /******************************************************************************* |
| * Copyright (c) 2000, 2019 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 |
| * Fraunhofer FIRST - extended API and implementation |
| * Technical University Berlin - extended API and implementation |
| * Stephen Herrmann <stephan@cs.tu-berlin.de> - Contributions for |
| * bug 317046 - Exception during debugging when hover mouse over a field |
| * bug 395002 - Self bound generic class doesn't resolve bounds properly for wildcards for certain parametrisation. |
| * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types |
| * bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files |
| * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis |
| * Bug 415291 - [1.8][null] differentiate type incompatibilities due to null annotations |
| * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. |
| * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) |
| * Bug 423504 - [1.8] Implement "18.5.3 Functional Interface Parameterization Inference" |
| * Bug 424712 - [1.8][compiler] NPE in TypeBinding.isProvablyDistinctTypeArgument |
| * Bug 426792 - [1.8][inference][impl] generify new type inference engine |
| * Bug 426764 - [1.8] Presence of conditional expression as method argument confuses compiler |
| * Bug 423505 - [1.8] Implement "18.5.4 More Specific Method Inference" |
| * Bug 427626 - [1.8] StackOverflow while typing new ArrayList<String>().toArray( and asking for code completion |
| * Bug 428019 - [1.8][compiler] Type inference failure with nested generic invocation. |
| * Bug 435962 - [RC2] StackOverFlowError when building |
| * Bug 438458 - [1.8][null] clean up handling of null type annotations wrt type variables |
| * Bug 440759 - [1.8][null] @NonNullByDefault should never affect wildcards and uses of a type variable |
| * Bug 441693 - [1.8][null] Bogus warning for type argument annotated with @NonNull |
| * Bug 446434 - [1.8][null] Enable interned captures also when analysing null type annotations |
| * Jesper S Moller <jesper@selskabet.org> - Contributions for |
| * bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression |
| * bug 527554 - [18.3] Compiler support for JEP 286 Local-Variable Type |
| * |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.compiler.lookup; |
| |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.jdt.core.compiler.CharOperation; |
| import org.eclipse.jdt.internal.compiler.ast.ASTNode; |
| import org.eclipse.jdt.internal.compiler.ast.Wildcard; |
| import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.util.RoleTypeCreator.TypeArgumentUpdater; |
| |
| /** |
| * OTDT changes: |
| * What: beautify signature for completion |
| * |
| * What: introduce new queries isRole() isTeam() valueParamSynthArgs() |
| * |
| * |
| * |
| * Not all fields defined by this type (& its subclasses) are initialized when it is created. |
| * Some are initialized only when needed. |
| * |
| * Accessors have been provided for some public fields so all TypeBindings have the same API... |
| * but access public fields directly whenever possible. |
| * Non-public fields have accessors which should be used everywhere you expect the field to be initialized. |
| * |
| * null is NOT a valid value for a non-public field... it just means the field is not initialized. |
| */ |
| abstract public class TypeBinding extends Binding { |
| |
| public int id = TypeIds.NoId; |
| public long tagBits = 0; // See values in the interface TagBits below |
| |
| protected AnnotationBinding [] typeAnnotations = Binding.NO_ANNOTATIONS; |
| |
| // jsr 308 |
| public static final ReferenceBinding TYPE_USE_BINDING = new ReferenceBinding() { /* used for type annotation resolution. */ |
| { this.id = TypeIds.T_undefined; } |
| @Override |
| public int kind() { return Binding.TYPE_USE; } |
| @Override |
| public boolean hasTypeBit(int bit) { return false; } |
| }; |
| |
| /** Base type definitions */ |
| public final static BaseTypeBinding INT = new BaseTypeBinding( |
| TypeIds.T_int, TypeConstants.INT, new char[] { 'I' }); |
| |
| public final static BaseTypeBinding BYTE = new BaseTypeBinding( |
| TypeIds.T_byte, TypeConstants.BYTE, new char[] { 'B' }); |
| |
| public final static BaseTypeBinding SHORT = new BaseTypeBinding( |
| TypeIds.T_short, TypeConstants.SHORT, new char[] { 'S' }); |
| |
| public final static BaseTypeBinding CHAR = new BaseTypeBinding( |
| TypeIds.T_char, TypeConstants.CHAR, new char[] { 'C' }); |
| |
| public final static BaseTypeBinding LONG = new BaseTypeBinding( |
| TypeIds.T_long, TypeConstants.LONG, new char[] { 'J' }); |
| |
| public final static BaseTypeBinding FLOAT = new BaseTypeBinding( |
| TypeIds.T_float, TypeConstants.FLOAT, new char[] { 'F' }); |
| |
| public final static BaseTypeBinding DOUBLE = new BaseTypeBinding( |
| TypeIds.T_double, TypeConstants.DOUBLE, new char[] { 'D' }); |
| |
| public final static BaseTypeBinding BOOLEAN = new BaseTypeBinding( |
| TypeIds.T_boolean, TypeConstants.BOOLEAN, new char[] { 'Z' }); |
| |
| public final static NullTypeBinding NULL = new NullTypeBinding(); |
| |
| public final static VoidTypeBinding VOID = new VoidTypeBinding(); |
| |
| |
| public TypeBinding() { |
| super(); |
| } |
| |
| public TypeBinding(TypeBinding prototype) { // faithfully copy most instance state - clone operation should specialize/override suitably. |
| this.id = prototype.id; |
| this.tagBits = prototype.tagBits & ~TagBits.AnnotationNullMASK; |
| } |
| |
| /** |
| * Match a well-known type id to its binding |
| */ |
| public static final TypeBinding wellKnownType(Scope scope, int id) { |
| switch (id) { |
| case TypeIds.T_boolean: |
| return TypeBinding.BOOLEAN; |
| case TypeIds.T_byte: |
| return TypeBinding.BYTE; |
| case TypeIds.T_char: |
| return TypeBinding.CHAR; |
| case TypeIds.T_short: |
| return TypeBinding.SHORT; |
| case TypeIds.T_double: |
| return TypeBinding.DOUBLE; |
| case TypeIds.T_float: |
| return TypeBinding.FLOAT; |
| case TypeIds.T_int: |
| return TypeBinding.INT; |
| case TypeIds.T_long: |
| return TypeBinding.LONG; |
| case TypeIds.T_JavaLangObject: |
| return scope.getJavaLangObject(); |
| case TypeIds.T_JavaLangString: |
| return scope.getJavaLangString(); |
| default: |
| return null; |
| } |
| } |
| |
| public ReferenceBinding actualType() { |
| return null; // overridden in ParameterizedTypeBinding & WildcardBinding |
| } |
| |
| TypeBinding [] additionalBounds() { |
| return null; // overridden in WildcardBinding |
| } |
| |
| public String annotatedDebugName() { |
| TypeBinding enclosingType = enclosingType(); |
| StringBuffer buffer = new StringBuffer(16); |
| if (enclosingType != null) { |
| buffer.append(enclosingType.annotatedDebugName()); |
| buffer.append('.'); |
| } |
| AnnotationBinding [] annotations = getTypeAnnotations(); |
| for (int i = 0, length = annotations == null ? 0 : annotations.length; i < length; i++) { |
| buffer.append(annotations[i]); |
| buffer.append(' '); |
| } |
| buffer.append(sourceName()); |
| return buffer.toString(); |
| } |
| |
| TypeBinding bound() { |
| return null; // overridden in WildcardBinding |
| } |
| |
| int boundKind() { |
| return -1; // overridden in WildcardBinding |
| } |
| |
| int rank() { |
| return -1; // overridden in WildcardBinding |
| } |
| |
| public ReferenceBinding containerAnnotationType() { |
| return null; |
| } |
| |
| /* Answer true if the receiver can be instantiated |
| */ |
| public boolean canBeInstantiated() { |
| return !isBaseType(); |
| } |
| |
| /** |
| * Perform capture conversion on a given type (only effective on parameterized type with wildcards) |
| */ |
| public TypeBinding capture(Scope scope, int start, int end) { |
| return this; |
| } |
| |
| /** |
| * Perform capture "deconversion" on a given type |
| */ |
| public TypeBinding uncapture(Scope scope) { |
| return this; |
| } |
| |
| /** |
| * In case of problems, returns the closest match found. It may not be perfect match, but the |
| * result of a best effort to improve fault-tolerance. |
| */ |
| public TypeBinding closestMatch() { |
| return this; // by default no better type |
| } |
| |
| /** |
| * Iterate through the type components to collect instances of leaf missing types |
| * @param missingTypes |
| * @return missing types |
| */ |
| public List<TypeBinding> collectMissingTypes(List<TypeBinding> missingTypes) { |
| return missingTypes; |
| } |
| |
| /** |
| * Collect the substitutes into a map for certain type variables inside the receiver type |
| * e.g. Collection<T>.findSubstitute(T, Collection<List<X>>): T --> List<X> |
| * Constraints: |
| * A << F corresponds to: F.collectSubstitutes(..., A, ..., CONSTRAINT_EXTENDS (1)) |
| * A = F corresponds to: F.collectSubstitutes(..., A, ..., CONSTRAINT_EQUAL (0)) |
| * A >> F corresponds to: F.collectSubstitutes(..., A, ..., CONSTRAINT_SUPER (2)) |
| */ |
| public void collectSubstitutes(Scope scope, TypeBinding actualType, InferenceContext inferenceContext, int constraint) { |
| // no substitute by default |
| } |
| |
| /** Virtual copy constructor: a copy is made of the receiver's entire instance state and then suitably |
| parameterized by the arguments to the clone operation as seen fit by each type. Parameters may not |
| make sense for every type in the hierarchy, in which case they are silently ignored. A type may |
| choose to retain a copy of the prototype for reference. |
| */ |
| public TypeBinding clone(TypeBinding enclosingType) { |
| throw new IllegalStateException("TypeBinding#clone() should have been overridden"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Answer the receiver's constant pool name. |
| * NOTE: This method should only be used during/after code gen. |
| * e.g. 'java/lang/Object' |
| */ |
| public abstract char[] constantPoolName(); |
| |
| public String debugName() { |
| return this.hasTypeAnnotations() ? annotatedDebugName() : new String(readableName()); |
| } |
| |
| /* |
| * Answer the receiver's dimensions - 0 for non-array types |
| */ |
| public int dimensions() { |
| return 0; |
| } |
| |
| public int depth() { |
| return 0; |
| } |
| |
| /* Answer the receiver's enclosing method ... null if the receiver is not a local type. |
| */ |
| public MethodBinding enclosingMethod() { |
| return null; |
| } |
| |
| |
| /* Answer the receiver's enclosing type... null if the receiver is a top level type or is an array or a non reference type. |
| */ |
| public ReferenceBinding enclosingType() { |
| return null; |
| } |
| |
| public TypeBinding erasure() { |
| return this; |
| } |
| |
| /** |
| * Perform an upwards type projection as per JLS 4.10.5 |
| * @param scope Relevant scope for evaluating type projection |
| * @param mentionedTypeVariables Filter for mentioned type variabled |
| * @returns Upwards type projection of 'this', or null if downwards projection is undefined |
| */ |
| public TypeBinding upwardsProjection(Scope scope, TypeBinding[] mentionedTypeVariables) { |
| return this; |
| } |
| |
| /** |
| * Perform a downwards type projection as per JLS 4.10.5 |
| * @param scope Relevant scope for evaluating type projection |
| * @param mentionedTypeVariables Filter for mentioned type variabled |
| * @returns Downwards type projection of 'this', or null if downwards projection is undefined |
| */ |
| public TypeBinding downwardsProjection(Scope scope, TypeBinding[] mentionedTypeVariables) { |
| return this; |
| } |
| |
| /** |
| * Find supertype which originates from a given well-known type, or null if not found |
| * (using id avoids triggering the load of well-known type: 73740) |
| * NOTE: only works for erasures of well-known types, as random other types may share |
| * same id though being distincts. |
| * @see TypeIds |
| */ |
| public ReferenceBinding findSuperTypeOriginatingFrom(int wellKnownOriginalID, boolean originalIsClass) { |
| |
| if (!(this instanceof ReferenceBinding)) return null; |
| ReferenceBinding reference = (ReferenceBinding) this; |
| |
| // do not allow type variables to match with erasures for free |
| if (reference.id == wellKnownOriginalID || (original().id == wellKnownOriginalID)) return reference; |
| |
| ReferenceBinding currentType = reference; |
| // iterate superclass to avoid recording interfaces if searched supertype is class |
| if (originalIsClass) { |
| while ((currentType = currentType.superclass()) != null) { |
| if (currentType.id == wellKnownOriginalID) |
| return currentType; |
| if (currentType.original().id == wellKnownOriginalID) |
| return currentType; |
| } |
| return null; |
| } |
| ReferenceBinding[] interfacesToVisit = null; |
| int nextPosition = 0; |
| do { |
| ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); |
| if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) { |
| if (interfacesToVisit == null) { |
| interfacesToVisit = itsInterfaces; |
| nextPosition = interfacesToVisit.length; |
| } else { |
| int itsLength = itsInterfaces.length; |
| if (nextPosition + itsLength >= interfacesToVisit.length) |
| System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition); |
| nextInterface : for (int a = 0; a < itsLength; a++) { |
| ReferenceBinding next = itsInterfaces[a]; |
| for (int b = 0; b < nextPosition; b++) |
| if (TypeBinding.equalsEquals(next, interfacesToVisit[b])) continue nextInterface; |
| interfacesToVisit[nextPosition++] = next; |
| } |
| } |
| } |
| } while ((currentType = currentType.superclass()) != null); |
| |
| for (int i = 0; i < nextPosition; i++) { |
| currentType = interfacesToVisit[i]; |
| if (currentType.id == wellKnownOriginalID) |
| return currentType; |
| if (currentType.original().id == wellKnownOriginalID) |
| return currentType; |
| ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); |
| if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) { |
| int itsLength = itsInterfaces.length; |
| if (nextPosition + itsLength >= interfacesToVisit.length) |
| System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition); |
| nextInterface : for (int a = 0; a < itsLength; a++) { |
| ReferenceBinding next = itsInterfaces[a]; |
| for (int b = 0; b < nextPosition; b++) |
| if (TypeBinding.equalsEquals(next, interfacesToVisit[b])) continue nextInterface; |
| interfacesToVisit[nextPosition++] = next; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Find supertype which originates from a given type, or null if not found |
| */ |
| public TypeBinding findSuperTypeOriginatingFrom(TypeBinding otherType) { |
| if (equalsEquals(this, otherType)) return this; |
| if (otherType == null) return null; |
| switch(kind()) { |
| case Binding.ARRAY_TYPE : |
| ArrayBinding arrayType = (ArrayBinding) this; |
| int otherDim = otherType.dimensions(); |
| if (arrayType.dimensions != otherDim) { |
| switch(otherType.id) { |
| case TypeIds.T_JavaLangObject : |
| case TypeIds.T_JavaIoSerializable : |
| case TypeIds.T_JavaLangCloneable : |
| return otherType; |
| } |
| if (otherDim < arrayType.dimensions && otherType.leafComponentType().id == TypeIds.T_JavaLangObject) { |
| return otherType; // X[][] has Object[] as an implicit supertype |
| } |
| return null; |
| } |
| if (!(arrayType.leafComponentType instanceof ReferenceBinding)) return null; |
| TypeBinding leafSuperType = arrayType.leafComponentType.findSuperTypeOriginatingFrom(otherType.leafComponentType()); |
| if (leafSuperType == null) return null; |
| return arrayType.environment().createArrayType(leafSuperType, arrayType.dimensions); |
| |
| case Binding.TYPE_PARAMETER : |
| if (isCapture()) { |
| CaptureBinding capture = (CaptureBinding) this; |
| TypeBinding captureBound = capture.firstBound; |
| if (captureBound instanceof ArrayBinding) { |
| TypeBinding match = captureBound.findSuperTypeOriginatingFrom(otherType); |
| if (match != null) return match; |
| } |
| } |
| //$FALL-THROUGH$ |
| case Binding.TYPE : |
| case Binding.PARAMETERIZED_TYPE : |
| case Binding.GENERIC_TYPE : |
| case Binding.RAW_TYPE : |
| case Binding.WILDCARD_TYPE : |
| case Binding.INTERSECTION_TYPE: |
| // do not allow type variables/intersection types to match with erasures for free |
| otherType = otherType.original(); |
| if (equalsEquals(this, otherType)) |
| return this; |
| if (equalsEquals(original(), otherType)) |
| return this; |
| ReferenceBinding currentType = (ReferenceBinding)this; |
| if (!otherType.isInterface()) { |
| while ((currentType = currentType.superclass()) != null) { |
| if (equalsEquals(currentType, otherType)) |
| return currentType; |
| if (equalsEquals(currentType.original(), otherType)) |
| return currentType; |
| } |
| return null; |
| } |
| ReferenceBinding[] interfacesToVisit = null; |
| int nextPosition = 0; |
| do { |
| ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); |
| if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) { |
| if (interfacesToVisit == null) { |
| interfacesToVisit = itsInterfaces; |
| nextPosition = interfacesToVisit.length; |
| } else { |
| int itsLength = itsInterfaces.length; |
| if (nextPosition + itsLength >= interfacesToVisit.length) |
| System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition); |
| nextInterface : for (int a = 0; a < itsLength; a++) { |
| ReferenceBinding next = itsInterfaces[a]; |
| for (int b = 0; b < nextPosition; b++) |
| if (equalsEquals(next, interfacesToVisit[b])) continue nextInterface; |
| interfacesToVisit[nextPosition++] = next; |
| } |
| } |
| } |
| } while ((currentType = currentType.superclass()) != null); |
| |
| for (int i = 0; i < nextPosition; i++) { |
| currentType = interfacesToVisit[i]; |
| if (equalsEquals(currentType, otherType)) |
| return currentType; |
| if (equalsEquals(currentType.original(), otherType)) |
| return currentType; |
| ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); |
| if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) { |
| int itsLength = itsInterfaces.length; |
| if (nextPosition + itsLength >= interfacesToVisit.length) |
| System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition); |
| nextInterface : for (int a = 0; a < itsLength; a++) { |
| ReferenceBinding next = itsInterfaces[a]; |
| for (int b = 0; b < nextPosition; b++) |
| if (equalsEquals(next, interfacesToVisit[b])) continue nextInterface; |
| interfacesToVisit[nextPosition++] = next; |
| } |
| } |
| } |
| break; |
| case Binding.INTERSECTION_TYPE18: |
| IntersectionTypeBinding18 itb18 = (IntersectionTypeBinding18) this; |
| ReferenceBinding[] intersectingTypes = itb18.getIntersectingTypes(); |
| for (int i = 0, length = intersectingTypes.length; i < length; i++) { |
| TypeBinding superType = intersectingTypes[i].findSuperTypeOriginatingFrom(otherType); |
| if (superType != null) |
| return superType; |
| } |
| break; |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the type to use for generic cast, or null if none required |
| */ |
| public TypeBinding genericCast(TypeBinding targetType) { |
| if (TypeBinding.equalsEquals(this, targetType)) |
| return null; |
| TypeBinding targetErasure = targetType.erasure(); |
| // type var get replaced by upper bound |
| if (erasure().findSuperTypeOriginatingFrom(targetErasure) != null) |
| return null; |
| //{ObjectTeams: don't cast if lowering is needed instead: |
| TypeBinding erasure= erasure(); |
| if ( erasure.isRole() |
| && TypeBinding.equalsEquals(targetErasure, ((ReferenceBinding)erasure).baseclass())) |
| return null; |
| // SH} |
| return targetErasure; |
| } |
| |
| //{ObjectTeams: beautify for completion: |
| public char[] genericTypeSignature(boolean retrenchCallin) { |
| return genericTypeSignature(); // no difference here. |
| } |
| // SH} |
| /** |
| * Answer the receiver classfile signature. |
| * Arrays & base types do not distinguish between signature() & constantPoolName(). |
| * NOTE: This method should only be used during/after code gen. |
| */ |
| public char[] genericTypeSignature() { |
| return signature(); |
| } |
| |
| /** |
| * Return the supertype which would erase as a subtype of a given declaring class. |
| * If the receiver is already erasure compatible, then it will returned. If not, then will return the alternate lowest |
| * upper bound compatible with declaring class. |
| * NOTE: the declaringClass is already know to be compatible with the receiver |
| * @param declaringClass to look for |
| * @return the lowest erasure compatible type (considering alternate bounds) |
| */ |
| public TypeBinding getErasureCompatibleType(TypeBinding declaringClass) { |
| switch(kind()) { |
| case Binding.TYPE_PARAMETER : |
| TypeVariableBinding variable = (TypeVariableBinding) this; |
| if (variable.erasure().findSuperTypeOriginatingFrom(declaringClass) != null) { |
| return this; // no need for alternate receiver type |
| } |
| if (variable.superclass != null && variable.superclass.findSuperTypeOriginatingFrom(declaringClass) != null) { |
| return variable.superclass.getErasureCompatibleType(declaringClass); |
| } |
| for (int i = 0, otherLength = variable.superInterfaces.length; i < otherLength; i++) { |
| ReferenceBinding superInterface = variable.superInterfaces[i]; |
| if (superInterface.findSuperTypeOriginatingFrom(declaringClass) != null) { |
| return superInterface.getErasureCompatibleType(declaringClass); |
| } |
| } |
| return this; // only occur if passed null declaringClass for arraylength |
| case Binding.INTERSECTION_TYPE : |
| WildcardBinding intersection = (WildcardBinding) this; |
| if (intersection.erasure().findSuperTypeOriginatingFrom(declaringClass) != null) { |
| return this; // no need for alternate receiver type |
| } |
| if (intersection.superclass != null && intersection.superclass.findSuperTypeOriginatingFrom(declaringClass) != null) { |
| return intersection.superclass.getErasureCompatibleType(declaringClass); |
| } |
| for (int i = 0, otherLength = intersection.superInterfaces.length; i < otherLength; i++) { |
| ReferenceBinding superInterface = intersection.superInterfaces[i]; |
| if (superInterface.findSuperTypeOriginatingFrom(declaringClass) != null) { |
| return superInterface.getErasureCompatibleType(declaringClass); |
| } |
| } |
| return this; // only occur if passed null declaringClass for arraylength |
| case Binding.INTERSECTION_TYPE18: |
| ReferenceBinding[] intersectingTypes = ((IntersectionTypeBinding18) this).getIntersectingTypes(); |
| ReferenceBinding constantPoolType = intersectingTypes[0]; |
| if (constantPoolType.id == TypeIds.T_JavaLangObject && intersectingTypes.length > 1) |
| constantPoolType = intersectingTypes[1]; |
| if (constantPoolType.erasure().findSuperTypeOriginatingFrom(declaringClass) != null) { |
| return this; // no need for alternate receiver type |
| } |
| for (ReferenceBinding superBinding : intersectingTypes) { |
| if (superBinding.findSuperTypeOriginatingFrom(declaringClass) != null) { |
| return superBinding.getErasureCompatibleType(declaringClass); |
| } |
| } |
| return this; // should only occur if passed null declaringClass for arraylength |
| default : |
| return this; |
| } |
| } |
| |
| public abstract PackageBinding getPackage(); |
| |
| //{ObjectTeams: accessible across AbstractOTReferenceBinding (sitting in a different package): |
| protected |
| // SH} |
| void initializeForStaticImports() { |
| // only applicable to source types |
| } |
| |
| public final boolean isAnonymousType() { |
| return (this.tagBits & TagBits.IsAnonymousType) != 0; |
| } |
| |
| /* Answer true if the receiver is an array |
| */ |
| public final boolean isArrayType() { |
| return (this.tagBits & TagBits.IsArrayType) != 0; |
| } |
| |
| /* Answer true if the receiver is a base type |
| */ |
| public final boolean isBaseType() { |
| return (this.tagBits & TagBits.IsBaseType) != 0; |
| } |
| |
| /* Answer true if the receiver is a base type other than void or null |
| */ |
| public final boolean isPrimitiveType() { |
| return (this.tagBits & TagBits.IsBaseType) != 0 && this.id != TypeIds.T_void && this.id != TypeIds.T_null; |
| } |
| |
| /* Answer true if the receiver is a primitive type or a boxed primitive type |
| */ |
| public final boolean isPrimitiveOrBoxedPrimitiveType() { |
| if (isPrimitiveType()) |
| return true; |
| switch (this.id) { |
| case TypeIds.T_JavaLangBoolean : |
| case TypeIds.T_JavaLangByte : |
| case TypeIds.T_JavaLangCharacter : |
| case TypeIds.T_JavaLangShort : |
| case TypeIds.T_JavaLangDouble : |
| case TypeIds.T_JavaLangFloat : |
| case TypeIds.T_JavaLangInteger : |
| case TypeIds.T_JavaLangLong : |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| /* Answer true if the receiver is a boxed primitive type |
| */ |
| public boolean isBoxedPrimitiveType() { |
| switch (this.id) { |
| case TypeIds.T_JavaLangBoolean : |
| case TypeIds.T_JavaLangByte : |
| case TypeIds.T_JavaLangCharacter : |
| case TypeIds.T_JavaLangShort : |
| case TypeIds.T_JavaLangDouble : |
| case TypeIds.T_JavaLangFloat : |
| case TypeIds.T_JavaLangInteger : |
| case TypeIds.T_JavaLangLong : |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| /** |
| * Returns true if parameterized type AND not of the form List<?> |
| */ |
| public boolean isBoundParameterizedType() { |
| return false; |
| } |
| |
| /** |
| * Returns true if the type is the capture of some wildcard |
| */ |
| public boolean isCapture() { |
| return false; |
| } |
| |
| public boolean isClass() { |
| return false; |
| } |
| |
| /* Answer true if the receiver type can be assigned to the argument type (right) |
| */ |
| public boolean isCompatibleWith(TypeBinding right) { |
| return isCompatibleWith(right, null); // delegate from the old signature to the new implementation: |
| } |
| // version that allows to capture a type bound using 'scope': |
| public abstract boolean isCompatibleWith(TypeBinding right, /*@Nullable*/ Scope scope); |
| |
| public boolean isPotentiallyCompatibleWith(TypeBinding right, /*@Nullable*/ Scope scope) { |
| return isCompatibleWith(right, scope); |
| } |
| |
| /* Answer true if the receiver type can be assigned to the argument type (right) with boxing/unboxing applied. |
| */ |
| public boolean isBoxingCompatibleWith(TypeBinding right, /*@NonNull */ Scope scope) { |
| |
| if (right == null) |
| return false; |
| |
| if (TypeBinding.equalsEquals(this, right)) |
| return true; |
| |
| if (this.isCompatibleWith(right, scope)) |
| return true; |
| |
| if (this.isBaseType() != right.isBaseType()) { |
| TypeBinding convertedType = scope.environment().computeBoxingType(this); |
| if (TypeBinding.equalsEquals(convertedType, right) || convertedType.isCompatibleWith(right, scope)) |
| return true; |
| } |
| return false; |
| } |
| |
| public boolean isEnum() { |
| return false; |
| } |
| |
| /** |
| * Returns true if a type is identical to another one, |
| * or for generic types, true if compared to its raw type. |
| */ |
| public boolean isEquivalentTo(TypeBinding otherType) { |
| if (equalsEquals(this, otherType)) |
| return true; |
| if (otherType == null) |
| return false; |
| switch (otherType.kind()) { |
| case Binding.WILDCARD_TYPE : |
| case Binding.INTERSECTION_TYPE : |
| return ((WildcardBinding) otherType).boundCheck(this); |
| } |
| return false; |
| } |
| |
| public boolean isGenericType() { |
| return false; |
| } |
| |
| /* Answer true if the receiver's hierarchy has problems (always false for arrays & base types) |
| */ |
| public final boolean isHierarchyInconsistent() { |
| return (this.tagBits & TagBits.HierarchyHasProblems) != 0; |
| } |
| |
| public boolean isInterface() { |
| return false; |
| } |
| |
| public boolean isFunctionalInterface(Scope scope) { |
| return false; |
| } |
| |
| /** |
| * Returns true if the current type denotes an intersection type: Number & Comparable<?> |
| */ |
| public boolean isIntersectionType() { |
| return false; |
| } |
| |
| public final boolean isLocalType() { |
| return (this.tagBits & TagBits.IsLocalType) != 0; |
| } |
| |
| public final boolean isMemberType() { |
| return (this.tagBits & TagBits.IsMemberType) != 0; |
| } |
| |
| public final boolean isNestedType() { |
| return (this.tagBits & TagBits.IsNestedType) != 0; |
| } |
| |
| public final boolean isNumericType() { |
| switch (this.id) { |
| case TypeIds.T_int: |
| case TypeIds.T_float: |
| case TypeIds.T_double: |
| case TypeIds.T_short: |
| case TypeIds.T_byte: |
| case TypeIds.T_long: |
| case TypeIds.T_char: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| //{ObjectTeams: |
| public boolean isTeam() { |
| return false; |
| } |
| public boolean isRole() { |
| return false; |
| } |
| public boolean isRoleType() { |
| return false; |
| } |
| public boolean isPlainDependentType() { |
| return false; |
| } |
| // SH} |
| |
| /** |
| * Returns true if the type is parameterized, e.g. List<String>. |
| * Note that some instances of ParameterizedTypeBinding have no arguments, like for non-generic members |
| * of a parameterized type. Use {@link #isParameterizedTypeWithActualArguments()} instead to find out. |
| */ |
| public boolean isParameterizedType() { |
| return false; |
| } |
| |
| /** |
| * Does this type or any of its details (array dimensions, type arguments) |
| * have a null type annotation? |
| */ |
| public boolean hasNullTypeAnnotations() { |
| return (this.tagBits & TagBits.HasNullTypeAnnotation) != 0; |
| } |
| /** |
| * Used to implement this sentence from o.e.j.annotation.DefaultLocation: |
| * "Wildcards and the use of type variables are always excluded from NonNullByDefault." |
| */ |
| public boolean acceptsNonNullDefault() { |
| return false; |
| } |
| |
| public boolean isIntersectionType18() { |
| return false; |
| } |
| |
| /** |
| * Returns true if the type is parameterized, e.g. List<String> |
| * Note that some instances of ParameterizedTypeBinding do answer false to {@link #isParameterizedType()} |
| * in case they have no arguments, like for non-generic members of a parameterized type. |
| * i.e. {@link #isParameterizedType()} is not equivalent to testing <code>type.kind() == Binding.PARAMETERIZED_TYPE</code> |
| */ |
| public final boolean isParameterizedTypeWithActualArguments() { |
| return (kind() == Binding.PARAMETERIZED_TYPE) |
| && ((ParameterizedTypeBinding) this).arguments != null; |
| } |
| |
| /** |
| * Returns true if the type is parameterized using its own type variables as arguments |
| */ |
| public boolean isParameterizedWithOwnVariables() { |
| if (kind() != Binding.PARAMETERIZED_TYPE) |
| return false; |
| ParameterizedTypeBinding paramType = (ParameterizedTypeBinding) this; |
| if (paramType.arguments == null) |
| return false; |
| TypeVariableBinding[] variables = erasure().typeVariables(); |
| for (int i = 0, length = variables.length; i < length; i++) { |
| if (TypeBinding.notEquals(variables[i], paramType.arguments[i])) |
| return false; |
| } |
| ReferenceBinding enclosing = paramType.enclosingType(); |
| if (enclosing != null && enclosing.erasure().isGenericType() |
| && !enclosing.isParameterizedWithOwnVariables()) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * JLS8 Sect 18.1.1 |
| * @param admitCapture18 request if {@link CaptureBinding18} shuld be considered as a proper type. |
| * If unsure say 'true', only in {@link Scope#greaterLowerBound(TypeBinding[], Scope, LookupEnvironment)} |
| * CaptureBinding18 has to be excluded to prevent an NPE on a branch that heuristically tries to avoid |
| * inconsistent intersections. |
| */ |
| public boolean isProperType(boolean admitCapture18) { |
| return true; |
| } |
| |
| public boolean isPolyType() { |
| return false; |
| } |
| |
| /** |
| * Substitute all occurrences of 'var' within the current type by 'substituteType. |
| * @param var an inference variable (JLS8 18.1.1) |
| * @param substituteType its substitution |
| * @return the current type after a substitution (either 'this' unmodified or a new type with the substitution molded in). |
| */ |
| //{ObjectTeams: cross the OT package, make protected: |
| protected |
| //SH} |
| TypeBinding substituteInferenceVariable(InferenceVariable var, TypeBinding substituteType) { |
| return this; // default: not substituting anything |
| } |
| |
| private boolean isProvableDistinctSubType(TypeBinding otherType) { |
| if (otherType.isInterface()) { |
| if (isInterface()) |
| return false; |
| if (isArrayType() |
| || ((this instanceof ReferenceBinding) && ((ReferenceBinding) this).isFinal()) |
| || (isTypeVariable() && ((TypeVariableBinding)this).superclass().isFinal())) { |
| return !isCompatibleWith(otherType); |
| } |
| return false; |
| } else { |
| if (isInterface()) { |
| if (otherType.isArrayType() |
| || ((otherType instanceof ReferenceBinding) && ((ReferenceBinding) otherType).isFinal()) |
| || (otherType.isTypeVariable() && ((TypeVariableBinding)otherType).superclass().isFinal())) { |
| return !isCompatibleWith(otherType); |
| } |
| } else { |
| if (!isTypeVariable() && !otherType.isTypeVariable()) { |
| return !isCompatibleWith(otherType); |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns true if a type is provably distinct from another one, |
| */ |
| public boolean isProvablyDistinct(TypeBinding otherType) { |
| |
| /* With the hybrid 1.4/1.5+ projects modes, while establishing type equivalence, we need to |
| be prepared for a type such as Map appearing in one of three forms: As (a) a ParameterizedTypeBinding |
| e.g Map<String, String>, (b) as RawTypeBinding Map#RAW and finally (c) as a BinaryTypeBinding |
| When the usage of a type lacks type parameters, whether we land up with the raw form or not depends |
| on whether the underlying type was "seen to be" a generic type in the particular build environment or |
| not. See: |
| https://bugs.eclipse.org/bugs/show_bug.cgi?id=186565 |
| https://bugs.eclipse.org/bugs/show_bug.cgi?id=328827 |
| https://bugs.eclipse.org/bugs/show_bug.cgi?id=329588 |
| */ |
| |
| if (equalsEquals(this, otherType)) |
| return false; |
| if (otherType == null) |
| return true; |
| |
| switch (kind()) { |
| |
| case Binding.PARAMETERIZED_TYPE : |
| ParameterizedTypeBinding paramType = (ParameterizedTypeBinding) this; |
| switch(otherType.kind()) { |
| case Binding.PARAMETERIZED_TYPE : |
| ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType; |
| if (notEquals(paramType.genericType(), otherParamType.genericType())) |
| return true; |
| if (!paramType.isStatic()) { // static member types do not compare their enclosing |
| ReferenceBinding enclosing = enclosingType(); |
| if (enclosing != null) { |
| ReferenceBinding otherEnclosing = otherParamType.enclosingType(); |
| if (otherEnclosing == null) return true; |
| if ((otherEnclosing.tagBits & TagBits.HasDirectWildcard) == 0) { |
| if (enclosing.isProvablyDistinct(otherEnclosing)) return true; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=302919 |
| } else { |
| if (!enclosing.isEquivalentTo(otherParamType.enclosingType())) return true; |
| } |
| } |
| } |
| int length = paramType.arguments == null ? 0 : paramType.arguments.length; |
| TypeBinding[] otherArguments = otherParamType.arguments; |
| int otherLength = otherArguments == null ? 0 : otherArguments.length; |
| if (otherLength != length) |
| return true; |
| for (int i = 0; i < length; i++) { |
| if (paramType.arguments[i].isProvablyDistinctTypeArgument(otherArguments[i], paramType, i)) |
| return true; |
| } |
| return false; |
| |
| case Binding.GENERIC_TYPE : |
| if (notEquals(paramType.genericType(), otherType)) |
| return true; |
| if (!paramType.isStatic()) { // static member types do not compare their enclosing |
| ReferenceBinding enclosing = enclosingType(); |
| if (enclosing != null) { |
| ReferenceBinding otherEnclosing = otherType.enclosingType(); |
| if (otherEnclosing == null) return true; |
| if ((otherEnclosing.tagBits & TagBits.HasDirectWildcard) == 0) { |
| if (notEquals(enclosing, otherEnclosing)) return true; |
| } else { |
| if (!enclosing.isEquivalentTo(otherType.enclosingType())) return true; |
| } |
| } |
| } |
| length = paramType.arguments == null ? 0 : paramType.arguments.length; |
| otherArguments = otherType.typeVariables(); |
| otherLength = otherArguments == null ? 0 : otherArguments.length; |
| if (otherLength != length) |
| return true; |
| for (int i = 0; i < length; i++) { |
| if (paramType.arguments[i].isProvablyDistinctTypeArgument(otherArguments[i], paramType, i)) |
| return true; |
| } |
| return false; |
| |
| case Binding.RAW_TYPE : |
| return notEquals(erasure(), otherType.erasure()); |
| case Binding.TYPE: // https://bugs.eclipse.org/bugs/show_bug.cgi?id=329588 |
| //{ObjectTeams: dependent types? |
| /* orig: |
| return notEquals(erasure(), otherType); |
| :giro */ |
| return distinctRealTypes(erasure(), otherType); |
| // SH} |
| } |
| return true; |
| |
| case Binding.RAW_TYPE : // dead code ?? |
| |
| switch(otherType.kind()) { |
| |
| case Binding.GENERIC_TYPE : |
| case Binding.PARAMETERIZED_TYPE : |
| case Binding.RAW_TYPE : |
| case Binding.TYPE: // https://bugs.eclipse.org/bugs/show_bug.cgi?id=329588 |
| //{ObjectTeams: dependent types? |
| /* orig: |
| return notEquals(erasure(), otherType.erasure()); |
| :giro */ |
| return distinctRealTypes(erasure(), otherType.erasure()); |
| // SH} |
| } |
| return true; |
| |
| case Binding.TYPE: // https://bugs.eclipse.org/bugs/show_bug.cgi?id=329588 |
| switch(otherType.kind()) { |
| case Binding.PARAMETERIZED_TYPE : |
| case Binding.RAW_TYPE : |
| return notEquals(this, otherType.erasure()); |
| } |
| break; |
| |
| default : |
| break; |
| } |
| return true; |
| } |
| //{ObjectTeams: relax if at least one type is a dependent type binding: |
| boolean distinctRealTypes(TypeBinding one, TypeBinding two) { |
| if (one instanceof ReferenceBinding && two instanceof ReferenceBinding) |
| if (one instanceof DependentTypeBinding || two instanceof DependentTypeBinding) |
| return notEquals(((ReferenceBinding)one).getRealType(), ((ReferenceBinding)two).getRealType()); |
| return TypeBinding.notEquals(one, two); |
| } |
| // SH} |
| |
| /** |
| * Returns false if two given types could not intersect as argument types: |
| * List<Throwable> & List<Runnable> --> false |
| * List<? extends Throwable> & List<? extends Runnable> --> true |
| * List<? extends String> & List<? extends Runnable> --> false |
| */ |
| private boolean isProvablyDistinctTypeArgument(TypeBinding otherArgument, final ParameterizedTypeBinding paramType, final int rank) { |
| if (TypeBinding.equalsEquals(this, otherArgument)) |
| return false; |
| |
| TypeBinding upperBound1 = null; |
| TypeBinding lowerBound1 = null; |
| ReferenceBinding genericType = paramType.genericType(); |
| switch (kind()) { |
| case Binding.WILDCARD_TYPE : |
| WildcardBinding wildcard = (WildcardBinding) this; |
| switch (wildcard.boundKind) { |
| case Wildcard.EXTENDS: |
| upperBound1 = wildcard.bound; |
| break; |
| case Wildcard.SUPER: |
| lowerBound1 = wildcard.bound; |
| break; |
| case Wildcard.UNBOUND: |
| return false; |
| } |
| break; |
| case Binding.INTERSECTION_TYPE : |
| break; |
| case Binding.TYPE_PARAMETER : |
| final TypeVariableBinding variable = (TypeVariableBinding) this; |
| if (variable.isCapture()) { |
| if (variable instanceof CaptureBinding18) { |
| CaptureBinding18 cb18 = (CaptureBinding18)variable; |
| upperBound1 = cb18.firstBound; |
| lowerBound1 = cb18.lowerBound; |
| } else { |
| CaptureBinding capture = (CaptureBinding) variable; |
| switch (capture.wildcard.boundKind) { |
| case Wildcard.EXTENDS: |
| upperBound1 = capture.wildcard.bound; |
| break; |
| case Wildcard.SUPER: |
| lowerBound1 = capture.wildcard.bound; |
| break; |
| case Wildcard.UNBOUND: |
| return false; |
| } |
| } |
| break; |
| } |
| if (variable.firstBound == null) // unbound variable |
| return false; |
| TypeBinding eliminatedType = Scope.convertEliminatingTypeVariables(variable, genericType, rank, null); |
| switch (eliminatedType.kind()) { |
| case Binding.WILDCARD_TYPE : |
| case Binding.INTERSECTION_TYPE : |
| wildcard = (WildcardBinding) eliminatedType; |
| switch (wildcard.boundKind) { |
| case Wildcard.EXTENDS: |
| upperBound1 = wildcard.bound; |
| break; |
| case Wildcard.SUPER: |
| lowerBound1 = wildcard.bound; |
| break; |
| case Wildcard.UNBOUND: |
| return false; |
| } |
| break; |
| } |
| break; |
| } |
| TypeBinding upperBound2 = null; |
| TypeBinding lowerBound2 = null; |
| switch (otherArgument.kind()) { |
| case Binding.WILDCARD_TYPE : |
| WildcardBinding otherWildcard = (WildcardBinding) otherArgument; |
| switch (otherWildcard.boundKind) { |
| case Wildcard.EXTENDS: |
| upperBound2 = otherWildcard.bound; |
| break; |
| case Wildcard.SUPER: |
| lowerBound2 = otherWildcard.bound; |
| break; |
| case Wildcard.UNBOUND: |
| return false; |
| } |
| break; |
| case Binding.INTERSECTION_TYPE : |
| break; |
| case Binding.TYPE_PARAMETER : |
| TypeVariableBinding otherVariable = (TypeVariableBinding) otherArgument; |
| if (otherVariable.isCapture()) { |
| if (otherVariable instanceof CaptureBinding18) { |
| CaptureBinding18 cb18 = (CaptureBinding18)otherVariable; |
| upperBound2 = cb18.firstBound; |
| lowerBound2 = cb18.lowerBound; |
| } else { |
| CaptureBinding otherCapture = (CaptureBinding) otherVariable; |
| switch (otherCapture.wildcard.boundKind) { |
| case Wildcard.EXTENDS: |
| upperBound2 = otherCapture.wildcard.bound; |
| break; |
| case Wildcard.SUPER: |
| lowerBound2 = otherCapture.wildcard.bound; |
| break; |
| case Wildcard.UNBOUND: |
| return false; |
| } |
| } |
| break; |
| } |
| if (otherVariable.firstBound == null) // unbound variable |
| return false; |
| TypeBinding otherEliminatedType = Scope.convertEliminatingTypeVariables(otherVariable, genericType, rank, null); |
| switch (otherEliminatedType.kind()) { |
| case Binding.WILDCARD_TYPE : |
| case Binding.INTERSECTION_TYPE : |
| otherWildcard = (WildcardBinding) otherEliminatedType; |
| switch (otherWildcard.boundKind) { |
| case Wildcard.EXTENDS: |
| upperBound2 = otherWildcard.bound; |
| break; |
| case Wildcard.SUPER: |
| lowerBound2 = otherWildcard.bound; |
| break; |
| case Wildcard.UNBOUND: |
| return false; |
| } |
| break; |
| } break; |
| } |
| if (lowerBound1 != null) { |
| if (lowerBound2 != null) { |
| return false; // Object could always be a candidate |
| |
| } else if (upperBound2 != null) { |
| if (lowerBound1.isTypeVariable() || upperBound2.isTypeVariable()) { |
| return false; |
| } |
| return !lowerBound1.isCompatibleWith(upperBound2); |
| } else { |
| if (lowerBound1.isTypeVariable() || otherArgument.isTypeVariable()) { |
| return false; |
| } |
| return !lowerBound1.isCompatibleWith(otherArgument); |
| } |
| } else if (upperBound1 != null) { |
| if (lowerBound2 != null) { |
| return !lowerBound2.isCompatibleWith(upperBound1); |
| } else if (upperBound2 != null) { |
| return upperBound1.isProvableDistinctSubType(upperBound2) |
| && upperBound2.isProvableDistinctSubType(upperBound1); |
| } else { |
| return otherArgument.isProvableDistinctSubType(upperBound1); |
| } |
| } else { |
| if (lowerBound2 != null) { |
| if (lowerBound2.isTypeVariable() || isTypeVariable()) { |
| return false; |
| } |
| return !lowerBound2.isCompatibleWith(this); |
| } else if (upperBound2 != null) { |
| return isProvableDistinctSubType(upperBound2); |
| } else { |
| return true; // ground types should have been the same |
| } |
| } |
| } |
| |
| /** |
| * Answer true if the receiver is an annotation which may be repeatable. Overridden as appropriate. |
| */ |
| public boolean isRepeatableAnnotationType() { |
| return false; |
| } |
| |
| public final boolean isRawType() { |
| return kind() == Binding.RAW_TYPE; |
| } |
| /** |
| * JLS(3) 4.7. |
| * Note: Foo<?>.Bar is also reifiable |
| */ |
| public boolean isReifiable() { |
| TypeBinding leafType = leafComponentType(); |
| if (!(leafType instanceof ReferenceBinding)) |
| return true; |
| ReferenceBinding current = (ReferenceBinding) leafType; |
| do { |
| switch (current.kind()) { |
| case Binding.TYPE_PARAMETER: |
| case Binding.WILDCARD_TYPE: |
| case Binding.INTERSECTION_TYPE: |
| case Binding.GENERIC_TYPE: |
| return false; |
| case Binding.PARAMETERIZED_TYPE: |
| if (current.isBoundParameterizedType()) |
| return false; |
| break; |
| case Binding.RAW_TYPE: |
| return true; |
| } |
| if (current.isStatic()) { |
| return true; |
| } |
| if (current.isLocalType()) { |
| LocalTypeBinding localTypeBinding = (LocalTypeBinding) current.erasure(); |
| MethodBinding enclosingMethod = localTypeBinding.enclosingMethod; |
| if (enclosingMethod != null && enclosingMethod.isStatic()) { |
| return true; |
| } |
| } |
| } while ((current = current.enclosingType()) != null); |
| return true; |
| } |
| |
| /** |
| * Answer true if the receiver is a static member type (or toplevel) |
| */ |
| public boolean isStatic() { |
| return false; |
| } |
| |
| /** |
| * Returns true if a given type may be thrown |
| */ |
| public boolean isThrowable() { |
| return false; |
| } |
| // JLS3: 4.5.1.1 |
| public boolean isTypeArgumentContainedBy(TypeBinding otherType) { |
| //{ObjectTeams: only slightly weaker form of identity: |
| /* orig: |
| if (TypeBinding.equalsEquals(this, otherType)) |
| :giro */ |
| if (RoleTypeBinding.eq(this, otherType)) |
| // SH} |
| return true; |
| switch (otherType.kind()) { |
| // handle captured wildcards. |
| case Binding.TYPE_PARAMETER: { |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=347426 |
| if (!isParameterizedType() || !otherType.isCapture()) { |
| return false; |
| } |
| CaptureBinding capture = (CaptureBinding) otherType; |
| if (capture instanceof CaptureBinding18) { |
| // by analogy to CaptureBinding but accepting the fact that .wildcard is null: |
| CaptureBinding18 cb18 = (CaptureBinding18) capture; |
| if (cb18.firstBound != null) { |
| if (cb18.lowerBound != null) |
| return false; // type containment is not defined for variables with both upper and lower bound |
| TypeBinding[] otherBounds = null; |
| int len = cb18.upperBounds.length; // by construction non-null if firstBound is set |
| if (len > 1) |
| System.arraycopy(cb18.upperBounds, 1, otherBounds = new TypeBinding[len-1], 0, len-1); |
| otherType = capture.environment.createWildcard(null, 0, cb18.firstBound, otherBounds, Wildcard.EXTENDS); |
| } else if (cb18.lowerBound != null) { |
| otherType = capture.environment.createWildcard(null, 0, cb18.lowerBound, null, Wildcard.SUPER); |
| } else { |
| return false; // not wellformed |
| } |
| } else { |
| TypeBinding upperBound = null; |
| TypeBinding [] otherBounds = null; |
| WildcardBinding wildcard = capture.wildcard; |
| switch (wildcard.boundKind) { |
| case Wildcard.SUPER: |
| return false; // T super syntax isn't allowed, impossible capture. |
| case Wildcard.UNBOUND: |
| TypeVariableBinding variable = wildcard.genericType.typeVariables()[wildcard.rank]; |
| upperBound = variable.upperBound(); |
| otherBounds = variable.boundsCount() > 1 ? variable.otherUpperBounds() : null; |
| break; |
| case Wildcard.EXTENDS: |
| upperBound = wildcard.bound; |
| otherBounds = wildcard.otherBounds; |
| break; |
| } |
| // Given class A<T extends B<?>>, A<?> cannot be the universe of all parameterizations of A |
| if (upperBound.id == TypeIds.T_JavaLangObject && otherBounds == null) { |
| return false; // but given class A<T>, A<?> stays an unbounded wildcard, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=348956 |
| } |
| otherType = capture.environment.createWildcard(null, 0, upperBound, otherBounds, Wildcard.EXTENDS); |
| } |
| return isTypeArgumentContainedBy(otherType); |
| } |
| // allow wildcard containment |
| case Binding.WILDCARD_TYPE: |
| case Binding.INTERSECTION_TYPE: |
| |
| TypeBinding lowerBound = this; |
| TypeBinding upperBound = this; |
| switch (kind()) { |
| case Binding.WILDCARD_TYPE: |
| case Binding.INTERSECTION_TYPE: |
| WildcardBinding wildcard = (WildcardBinding) this; |
| switch (wildcard.boundKind) { |
| case Wildcard.EXTENDS: |
| if (wildcard.otherBounds != null) // intersection type |
| break; |
| upperBound = wildcard.bound; |
| lowerBound = null; |
| break; |
| case Wildcard.SUPER: |
| upperBound = wildcard; |
| lowerBound = wildcard.bound; |
| break; |
| case Wildcard.UNBOUND: |
| upperBound = wildcard; |
| lowerBound = null; |
| } |
| break; |
| case Binding.TYPE_PARAMETER: |
| if (isCapture()) { |
| CaptureBinding capture = (CaptureBinding) this; |
| if (capture.lowerBound != null) |
| lowerBound = capture.lowerBound; |
| } |
| } |
| WildcardBinding otherWildcard = (WildcardBinding) otherType; |
| if (otherWildcard.otherBounds != null) |
| return false; // not a true wildcard (intersection type) |
| TypeBinding otherBound = otherWildcard.bound; |
| switch (otherWildcard.boundKind) { |
| case Wildcard.EXTENDS: |
| if (otherBound instanceof IntersectionTypeBinding18) { |
| TypeBinding [] intersectingTypes = ((IntersectionTypeBinding18) otherBound).intersectingTypes; |
| for (int i = 0, length = intersectingTypes.length; i < length; i++) |
| if (TypeBinding.equalsEquals(intersectingTypes[i], this)) |
| return true; |
| } |
| if (TypeBinding.equalsEquals(otherBound, this)) |
| return true; // ? extends T <= ? extends ? extends T |
| if (upperBound == null) |
| return false; |
| TypeBinding match = upperBound.findSuperTypeOriginatingFrom(otherBound); |
| if (match != null && (match = match.leafComponentType()).isRawType()) { |
| return TypeBinding.equalsEquals(match, otherBound.leafComponentType()); // forbide: Collection <= ? extends Collection<?> |
| // forbide: Collection[] <= ? extends Collection<?>[] |
| } |
| return upperBound.isCompatibleWith(otherBound); |
| |
| case Wildcard.SUPER: |
| if (otherBound instanceof IntersectionTypeBinding18) { |
| TypeBinding [] intersectingTypes = ((IntersectionTypeBinding18) otherBound).intersectingTypes; |
| for (int i = 0, length = intersectingTypes.length; i < length; i++) |
| if (TypeBinding.equalsEquals(intersectingTypes[i], this)) |
| return true; |
| } |
| if (TypeBinding.equalsEquals(otherBound, this)) |
| return true; // ? super T <= ? super ? super T |
| if (lowerBound == null) |
| return false; |
| match = otherBound.findSuperTypeOriginatingFrom(lowerBound); |
| if (match != null && (match = match.leafComponentType()).isRawType()) { |
| return TypeBinding.equalsEquals(match, lowerBound.leafComponentType()); // forbide: Collection <= ? super Collection<?> |
| // forbide: Collection[] <= ? super Collection<?>[] |
| } |
| return otherBound.isCompatibleWith(lowerBound); |
| |
| case Wildcard.UNBOUND: |
| default: |
| return true; |
| } |
| // allow List<?> to match List<? extends Object> (and reciprocally) |
| case Binding.PARAMETERIZED_TYPE: |
| if (!isParameterizedType()) |
| return false; |
| ParameterizedTypeBinding paramType = (ParameterizedTypeBinding) this; |
| ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType; |
| if (TypeBinding.notEquals(paramType.actualType(), otherParamType.actualType())) |
| return false; |
| if (!paramType.isStatic()) { // static member types do not compare their enclosing |
| ReferenceBinding enclosing = enclosingType(); |
| if (enclosing != null) { |
| ReferenceBinding otherEnclosing = otherParamType .enclosingType(); |
| if (otherEnclosing == null) |
| return false; |
| if ((otherEnclosing.tagBits & TagBits.HasDirectWildcard) == 0) { |
| if (TypeBinding.notEquals(enclosing, otherEnclosing)) |
| return false; |
| } else { |
| if (!enclosing.isTypeArgumentContainedBy(otherParamType.enclosingType())) |
| return false; |
| } |
| } |
| } |
| int length = paramType.arguments == null ? 0 : paramType.arguments.length; |
| TypeBinding[] otherArguments = otherParamType.arguments; |
| int otherLength = otherArguments == null ? 0 : otherArguments.length; |
| if (otherLength != length) |
| return false; |
| nextArgument: for (int i = 0; i < length; i++) { |
| TypeBinding argument = paramType.arguments[i]; |
| TypeBinding otherArgument = otherArguments[i]; |
| if (TypeBinding.equalsEquals(argument, otherArgument)) |
| continue nextArgument; |
| int kind = argument.kind(); |
| if (otherArgument.kind() != kind) |
| return false; |
| switch (kind) { |
| case Binding.PARAMETERIZED_TYPE: |
| if (argument.isTypeArgumentContainedBy(otherArgument)) // recurse |
| continue nextArgument; |
| break; |
| case Binding.WILDCARD_TYPE: |
| case Binding.INTERSECTION_TYPE: |
| WildcardBinding wildcard = (WildcardBinding) argument; |
| otherWildcard = (WildcardBinding) otherArgument; |
| switch (wildcard.boundKind) { |
| case Wildcard.EXTENDS: |
| // match "? extends <upperBound>" with "?" |
| if (otherWildcard.boundKind == Wildcard.UNBOUND |
| && TypeBinding.equalsEquals(wildcard.bound, wildcard.typeVariable().upperBound())) |
| continue nextArgument; |
| break; |
| case Wildcard.SUPER: |
| break; |
| case Wildcard.UNBOUND: |
| // match "?" with "? extends <upperBound>" |
| if (otherWildcard.boundKind == Wildcard.EXTENDS |
| && TypeBinding.equalsEquals(otherWildcard.bound, otherWildcard.typeVariable().upperBound())) |
| continue nextArgument; |
| break; |
| } |
| break; |
| } |
| return false; |
| } |
| return true; |
| } |
| // (? super Object) <= Object |
| if (otherType.id == TypeIds.T_JavaLangObject) { |
| switch (kind()) { |
| case Binding.WILDCARD_TYPE: |
| WildcardBinding wildcard = (WildcardBinding) this; |
| if (wildcard.boundKind == Wildcard.SUPER && wildcard.bound.id == TypeIds.T_JavaLangObject) { |
| return true; |
| } |
| break; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns true if the type was declared as a type variable |
| */ |
| public boolean isTypeVariable() { |
| return false; |
| } |
| |
| /** |
| * Returns true if wildcard type of the form '?' (no bound) |
| */ |
| public boolean isUnboundWildcard() { |
| return false; |
| } |
| |
| /** |
| * Returns true if the type is a subclass of java.lang.Error or java.lang.RuntimeException |
| */ |
| public boolean isUncheckedException(boolean includeSupertype) { |
| return false; |
| } |
| |
| /** |
| * Returns true if the type is a wildcard |
| */ |
| public boolean isWildcard() { |
| return false; |
| } |
| |
| /* API |
| * Answer the receiver's binding type from Binding.BindingID. |
| */ |
| @Override |
| public int kind() { |
| return Binding.TYPE; |
| } |
| |
| public TypeBinding leafComponentType() { |
| return this; |
| } |
| |
| /** |
| * Meant to be invoked on compatible types, to figure if unchecked conversion is necessary |
| */ |
| public boolean needsUncheckedConversion(TypeBinding targetType) { |
| |
| if (TypeBinding.equalsEquals(this, targetType)) |
| return false; |
| targetType = targetType.leafComponentType(); |
| if (!(targetType instanceof ReferenceBinding)) |
| return false; |
| |
| TypeBinding currentType = leafComponentType(); |
| TypeBinding match = currentType.findSuperTypeOriginatingFrom(targetType); |
| if (!(match instanceof ReferenceBinding)) |
| return false; |
| ReferenceBinding compatible = (ReferenceBinding) match; |
| while (compatible.isRawType()) { |
| if (targetType.isBoundParameterizedType()) |
| return true; |
| if (compatible.isStatic()) |
| break; |
| if ((compatible = compatible.enclosingType()) == null) |
| break; |
| if ((targetType = targetType.enclosingType()) == null) |
| break; |
| } |
| return false; |
| } |
| |
| /** Answer a readable name (for error reporting) that includes nullness type annotations. */ |
| public char[] nullAnnotatedReadableName(CompilerOptions options, boolean shortNames) /* e.g.: java.lang.Object @o.e.j.a.NonNull[] */ { |
| if (shortNames) |
| return shortReadableName(); |
| else |
| return readableName(); |
| } |
| |
| /** |
| * Returns the orignal generic type instantiated by the receiver type, or itself if not. |
| * This is similar to erasure process, except it doesn't erase type variable, wildcard, intersection types etc... |
| */ |
| public TypeBinding original() { |
| switch(kind()) { |
| case Binding.PARAMETERIZED_TYPE : |
| case Binding.RAW_TYPE : |
| case Binding.ARRAY_TYPE : |
| return erasure().unannotated(); |
| default : |
| return this.unannotated(); |
| } |
| } |
| |
| /** |
| * Return this type minus its type annotations |
| */ |
| public TypeBinding unannotated() { |
| return this; |
| } |
| |
| /** |
| * Return this type minus its toplevel null annotations. Any annotations on type arguments or |
| * bounds are retained. |
| */ |
| public TypeBinding withoutToplevelNullAnnotation() { |
| return this; |
| } |
| |
| //{ObjectTeams: we need to override this method: |
| /* orig: |
| public final boolean hasTypeAnnotations() { |
| :giro */ |
| public boolean hasTypeAnnotations() { |
| // SH} |
| return (this.tagBits & TagBits.HasTypeAnnotations) != 0; |
| } |
| |
| /** |
| * Answer the qualified name of the receiver's package separated by periods |
| * or an empty string if its the default package. |
| * |
| * For example, {java.util}. |
| */ |
| |
| public char[] qualifiedPackageName() { |
| PackageBinding packageBinding = getPackage(); |
| return packageBinding == null |
| || packageBinding.compoundName == CharOperation.NO_CHAR_CHAR ? CharOperation.NO_CHAR |
| : packageBinding.readableName(); |
| } |
| |
| /** |
| * Answer the source name for the type. |
| * In the case of member types, as the qualified name from its top level type. |
| * For example, for a member type N defined inside M & A: "A.M.N". |
| */ |
| |
| public abstract char[] qualifiedSourceName(); |
| |
| /** |
| * @return the JSR 308 annotations for this type. |
| */ |
| final public AnnotationBinding[] getTypeAnnotations() { |
| return this.typeAnnotations; |
| } |
| |
| public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) { |
| this.tagBits |= TagBits.HasTypeAnnotations; |
| if (annotations == null || annotations.length == 0) |
| return; |
| this.typeAnnotations = annotations; |
| if (evalNullAnnotations) { |
| for (int i = 0, length = annotations.length; i < length; i++) { |
| AnnotationBinding annotation = annotations[i]; |
| if (annotation != null) { |
| if (annotation.type.hasNullBit(TypeIds.BitNullableAnnotation)) |
| this.tagBits |= TagBits.AnnotationNullable | TagBits.HasNullTypeAnnotation; |
| else if (annotation.type.hasNullBit(TypeIds.BitNonNullAnnotation)) |
| this.tagBits |= TagBits.AnnotationNonNull | TagBits.HasNullTypeAnnotation; |
| } |
| } |
| // we do accept contradictory tagBits here, to support detecting contradictions caused by type substitution |
| } |
| } |
| |
| // return a name that can be passed to Signature.createTypeSignature |
| public char [] signableName() { |
| return readableName(); |
| } |
| |
| /** |
| * Answer the receiver classfile signature. |
| * Arrays & base types do not distinguish between signature() & constantPoolName(). |
| * NOTE: This method should only be used during/after code gen. |
| */ |
| public char[] signature() { |
| return constantPoolName(); |
| } |
| |
| public abstract char[] sourceName(); |
| //{ObjectTeams: Raw type name. Not beautified. |
| public char[] internalName() { |
| return sourceName(); |
| } |
| // SH} |
| |
| public void swapUnresolved(UnresolvedReferenceBinding unresolvedType, |
| ReferenceBinding resolvedType, LookupEnvironment environment) { |
| // subclasses must override if they wrap another type binding |
| } |
| |
| //{ObjectTeams: visible across AbstractOTReferenceBinding (in a different package): |
| protected |
| // SH} |
| TypeBinding [] typeArguments () { |
| return null; |
| } |
| |
| public TypeVariableBinding[] typeVariables() { |
| return Binding.NO_TYPE_VARIABLES; |
| } |
| //{ObjectTeams: value parameters |
| /** Return the synthetic arguments representing value parameters. |
| * Note that each synthetic argument refers to the matchingField (final) |
| * by which client code can access the value parameter. |
| */ |
| public SyntheticArgumentBinding[] valueParamSynthArgs() { |
| return Binding.NO_SYNTH_ARGUMENTS; |
| } |
| public DependentTypeBinding asPlainDependentType() { |
| return null; // is not a dependent type |
| } |
| |
| |
| public TypeBinding maybeWrapRoleType (ASTNode typedNode, TypeArgumentUpdater updater) { |
| return this; |
| } |
| // SH} |
| |
| /** |
| * Return the single abstract method of a functional interface, or one of {@code null} or {@link ReferenceBinding#samProblemBinding}, if the receiver is not a functional interface as defined in JLS 9.8. |
| * In particular {@code null} is answered if the receiver is not a reference type, or is a problem type. |
| * @param scope scope |
| * @param replaceWildcards Should wildcards be replaced following JLS 9.8? Say false for lambdas with explicit argument types which should apply 18.5.3 |
| * |
| * @return The single abstract method of a functional interface, or one of {@code null} or {@link ReferenceBinding#samProblemBinding}, if the receiver is not a functional interface. |
| */ |
| public MethodBinding getSingleAbstractMethod(Scope scope, boolean replaceWildcards) { |
| return null; |
| } |
| |
| public ReferenceBinding[] getIntersectingTypes() { |
| return null; |
| } |
| |
| public static boolean equalsEquals(TypeBinding that, TypeBinding other) { |
| if (that == other) //$IDENTITY-COMPARISON$ |
| return true; |
| if (that == null || other == null) |
| return false; |
| if (that.id != TypeIds.NoId && that.id == other.id) |
| return true; |
| if (that instanceof LocalTypeBinding && other instanceof LocalTypeBinding) { |
| // while a lambda is being resolved, consider a local type as equal to its variant from another lambda copy |
| return ((LocalTypeBinding) that).sourceStart == ((LocalTypeBinding) other).sourceStart; |
| } |
| return false; |
| } |
| |
| public static boolean notEquals(TypeBinding that, TypeBinding other) { |
| if (that == other) //$IDENTITY-COMPARISON$ |
| return false; |
| if (that == null || other == null) |
| return true; |
| if (that.id != TypeIds.NoId && that.id == other.id) |
| return false; |
| return true; |
| } |
| /** Return the primordial type from which the receiver was cloned. Not all types track a prototype, only {@link SourceTypeBinding}, |
| * {@link BinaryTypeBinding} and {@link UnresolvedReferenceBinding} do so as of now. In fact some types e.g {@link ParameterizedTypeBinding} |
| * should not do so. Deflecting a query to a prototype would lead to wrong results in the case of {@link ParameterizedTypeBinding} |
| */ |
| public TypeBinding prototype() { |
| return null; |
| } |
| |
| public boolean isUnresolvedType() { |
| return false; |
| } |
| |
| /** Does this type mention any of the given type parameters, except the one at position 'idx'? */ |
| public boolean mentionsAny(TypeBinding[] parameters, int idx) { |
| for (int i = 0; i < parameters.length; i++) |
| if (i != idx) |
| if (TypeBinding.equalsEquals(parameters[i], this)) |
| return true; |
| return false; |
| } |
| |
| /** Collect all inference variables mentioned in this type into the set 'variables'. */ |
| //{ObjectTeams: cross the OT package, make protected: |
| protected |
| // SH} |
| void collectInferenceVariables(Set<InferenceVariable> variables) { |
| // nop |
| } |
| /** Answer an additional bit characterizing this type, like {@link TypeIds#BitAutoCloseable}. */ |
| public boolean hasTypeBit(int bit) { |
| return false; |
| } |
| |
| public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope scope) { |
| return s.isCompatibleWith(t, scope) && !s.needsUncheckedConversion(t); |
| } |
| |
| public boolean isSubtypeOf(TypeBinding right, boolean simulatingBugJDK8026527) { |
| return isCompatibleWith(right); |
| } |
| |
| public MethodBinding[] getMethods(char[] selector) { |
| return Binding.NO_METHODS; |
| } |
| |
| public boolean canBeSeenBy(Scope scope) { |
| return true; |
| } |
| |
| public ReferenceBinding superclass() { |
| return null; |
| } |
| |
| public ReferenceBinding[] superInterfaces() { |
| return Binding.NO_SUPERINTERFACES; |
| } |
| |
| public SyntheticArgumentBinding[] syntheticOuterLocalVariables() { |
| return null; // is null if no enclosing instances are required |
| } |
| /** |
| * Call this before descending into type details to prevent infinite recursion. |
| * @return true if a recursion was not already started. |
| */ |
| public boolean enterRecursiveFunction() { |
| return true; |
| } |
| /** |
| * Exit the context of a potentially recursive function. |
| */ |
| public void exitRecursiveFunction() { |
| // empty, subclasses to override |
| } |
| |
| public boolean isFunctionalType() { |
| return false; |
| } |
| /** |
| * Refresh some tagBits from details into the main type. |
| * Currently handled: TagBits.HasNullTypeAnnotation |
| */ |
| public long updateTagBits() { |
| return this.tagBits & TagBits.HasNullTypeAnnotation; // subclasses to override |
| } |
| |
| public boolean isFreeTypeVariable() { |
| return false; |
| } |
| } |