blob: 60e58c48ff026b003b2eb5b580fa417fcfb1699f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2020 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
* Stephan Herrmann - Contributions for
* bug 349326 - [1.7] new warning for missing try-with-resources
* bug 186342 - [compiler][null] Using annotations for null checking
* bug 365519 - editorial cleanup after bug 186342 and bug 365387
* bug 358903 - Filter practically unimportant resource leak warnings
* bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults
* bug 388281 - [compiler][null] inheritance of null annotations as an option
* 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 400421 - [compiler] Null analysis for fields does not take @com.google.inject.Inject into account
* bug 382069 - [null] Make the null analysis consider JUnit's assertNotNull similarly to assertions
* 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 415043 - [1.8][null] Follow-up re null type annotations after bug 392099
* Bug 416176 - [1.8][compiler][null] null type annotations cause grief on type variables
* 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 426792 - [1.8][inference][impl] generify new type inference engine
* Bug 428019 - [1.8][compiler] Type inference failure with nested generic invocation.
* Bug 427199 - [1.8][resource] avoid resource leak warnings on Streams that have no resource
* Bug 418743 - [1.8][null] contradictory annotations on invocation of generic method not reported
* Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
* Bug 431581 - Eclipse compiles what it should not
* Bug 440759 - [1.8][null] @NonNullByDefault should never affect wildcards and uses of a type variable
* Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression
* Bug 446442 - [1.8] merge null annotations from super methods
* Bug 456532 - [1.8][null] ReferenceBinding.appendNullAnnotation() includes phantom annotations in error messages
* Bug 410218 - Optional warning for arguments of "unexpected" types to Map#get(Object), Collection#remove(Object) et al.
* Jesper S Moller - Contributions for
* bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
* bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
* bug 527554 - [18.3] Compiler support for JEP 286 Local-Variable Type
* Ulrich Grave <ulrich.grave@gmx.de> - Contributions for
* bug 386692 - Missing "unused" warning on "autowired" fields
* Pierre-Yves B. <pyvesdev@gmail.com> - Contribution for
* bug 542520 - [JUnit 5] Warning The method xxx from the type X is never used locally is shown when using MethodSource
* Sebastian Zarnekow - Contributions for
* bug 544921 - [performance] Poor performance with large source files
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
import java.util.Arrays;
import java.util.Comparator;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.InvalidInputException;
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.Dependencies;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.AbstractOTReferenceBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.TypeModel;
import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.RoleSplitter;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.TSuperHelper;
/*
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.
*/
/**
* OTDT changes:
*
* Note: New supertype AbstractOTReferenceBinding holds most of what we changed here.
*
*
* What: Slightly changed strategy for enclosingType
* Why: Binary local types don't set enclosingType, but role local types need it.
* Where BinaryTypeBinding.setEnclosingOfRoleLocal()
*
* What: new function attributeName()
* Why: in byte code attributes type names are encoded differently
*
* What: new functions getMemberTypeRecurse(name), getMethod(Scope scope, char[] selector)
* Why: need deep lookup.
*
* What: isStrictlyCompatibleWith()
* Why: confined types are not compatible to Object (which other methods assume)
*
* What: variants of printable names: filter out __OT__,
* Note: now sourceName and sourceName() have different semantics.
*
*/
//{ObjectTeams: changed superclass in order to separate out OT features:
abstract public class ReferenceBinding extends AbstractOTReferenceBinding {
@Override
protected ReferenceBinding _this() { return this; } // used in AbstractOTReferenceBinding to refer to 'this'
// SH}
public char[][] compoundName;
public char[] sourceName;
//{ObjectTeams: now in AbstractOTReferenceBinding:
/* orig:
public int modifiers;
:giro */
// SH}
public PackageBinding fPackage;
//{ObjectTeams: accessible for sub-classes:
/* orig:
char[] fileName;
char[] constantPoolName;
char[] signature;
:giro */
public char[] fileName;
public char[] constantPoolName;
protected char[] signature;
// SH}
private SimpleLookupTable compatibleCache;
int typeBits; // additional bits characterizing this type
protected MethodBinding [] singleAbstractMethod;
public static final ReferenceBinding LUB_GENERIC = new ReferenceBinding() { /* used for lub computation */
{ this.id = TypeIds.T_undefined; }
@Override
public boolean hasTypeBit(int bit) { return false; }
};
private static final Comparator<FieldBinding> FIELD_COMPARATOR = new Comparator<FieldBinding>() {
@Override
public int compare(FieldBinding o1, FieldBinding o2) {
char[] n1 = o1.name;
char[] n2 = o2.name;
return ReferenceBinding.compare(n1, n2, n1.length, n2.length);
}
};
private static final Comparator<MethodBinding> METHOD_COMPARATOR = new Comparator<MethodBinding>() {
@Override
public int compare(MethodBinding m1, MethodBinding m2) {
char[] s1 = m1.selector;
char[] s2 = m2.selector;
int c = ReferenceBinding.compare(s1, s2, s1.length, s2.length);
return c == 0 ? m1.parameters.length - m2.parameters.length : c;
}
};
static protected ProblemMethodBinding samProblemBinding = new ProblemMethodBinding(TypeConstants.ANONYMOUS_METHOD, null, ProblemReasons.NoSuchSingleAbstractMethod);
public ReferenceBinding(ReferenceBinding prototype) {
super(prototype);
this.compoundName = prototype.compoundName;
this.sourceName = prototype.sourceName;
this.modifiers = prototype.modifiers;
this.fPackage = prototype.fPackage;
this.fileName = prototype.fileName;
this.constantPoolName = prototype.constantPoolName;
this.signature = prototype.signature;
this.compatibleCache = prototype.compatibleCache;
this.typeBits = prototype.typeBits;
this.singleAbstractMethod = prototype.singleAbstractMethod;
//{ObjectTeams: most subclasses need model to be set:
this.model = new TypeModel(prototype.model, this);
// SH}
}
public ReferenceBinding() {
super();
//{ObjectTeams: most subclasses need model to be set:
this.model = new TypeModel(this);
// SH}
}
public static FieldBinding binarySearch(char[] name, FieldBinding[] sortedFields) {
if (sortedFields == null)
return null;
int max = sortedFields.length;
if (max == 0)
return null;
int left = 0, right = max - 1, nameLength = name.length;
int mid = 0;
char[] midName;
while (left <= right) {
mid = left + (right - left) /2;
int compare = compare(name, midName = sortedFields[mid].name, nameLength, midName.length);
if (compare < 0) {
right = mid-1;
} else if (compare > 0) {
left = mid+1;
} else {
return sortedFields[mid];
}
}
return null;
}
//{ObjectTeams:
public static FieldBinding[] sortedInsert(FieldBinding[] sortedFields, FieldBinding newField) {
if (sortedFields != null) {
int max = sortedFields.length;
if (max > 0) {
int insertBefore = 0;
char[] name = newField.name;
int left = 0, right = max - 1, nameLength = name.length;
int mid = 0;
char[] midName;
while (left <= right) {
mid = (left + right) /2;
int compare = compare(name, midName = sortedFields[mid].name, nameLength, midName.length);
if (compare < 0) {
right = mid-1;
insertBefore = mid;
} else if (compare > 0) {
left = mid+1;
insertBefore = mid+1;
} else {
insertBefore = mid;
break; // mid's name is equal to `name'
}
}
FieldBinding[] result = new FieldBinding[max+1];
System.arraycopy(sortedFields, 0, result, 0, insertBefore);
System.arraycopy(sortedFields, insertBefore, result, insertBefore+1, max-insertBefore);
result[insertBefore] = newField;
return result;
}
}
return new FieldBinding[] {newField};
}
public static MethodBinding[] sortedInsert(MethodBinding[] sortedMethods, MethodBinding newMethod) {
if (sortedMethods != null) {
int max = sortedMethods.length;
if (max > 0) {
int insertBefore = 0;
int left = 0, right = max - 1;
int mid = 0;
binarySearch:
while (left <= right) {
mid = (left + right) /2;
MethodBinding midM = sortedMethods[mid];
if (midM == null) {
// revert to linear search:
while (left <= right) {
midM = sortedMethods[right];
while (midM == null && left <= right)
midM = sortedMethods[--right];
int compare = METHOD_COMPARATOR.compare(newMethod, midM);
if (compare < 0) {
right--;
} else if (compare > 0) {
insertBefore = right+1;
break binarySearch;
} else {
insertBefore = right;
break binarySearch;
}
}
}
int compare = METHOD_COMPARATOR.compare(newMethod, midM);
if (compare < 0) {
right = mid-1;
insertBefore = mid;
} else if (compare > 0) {
left = mid+1;
insertBefore = mid+1;
} else {
insertBefore = mid;
break; // mid's name is equal to `name'
}
}
MethodBinding[] result = new MethodBinding[max+1];
System.arraycopy(sortedMethods, 0, result, 0, insertBefore);
System.arraycopy(sortedMethods, insertBefore, result, insertBefore+1, max-insertBefore);
result[insertBefore] = newMethod;
return result;
}
}
return new MethodBinding[] {newMethod};
}
// SH}
/**
* Returns a combined range value representing: (start + (end<<32)), where start is the index of the first matching method
* (remember methods are sorted alphabetically on selectors), and end is the index of last contiguous methods with same
* selector.
* -1 means no method got found
* @param selector
* @param sortedMethods
* @return (start + (end<<32)) or -1 if no method found
*/
public static long binarySearch(char[] selector, MethodBinding[] sortedMethods) {
if (sortedMethods == null)
return -1;
int max = sortedMethods.length;
if (max == 0)
return -1;
int left = 0, right = max - 1, selectorLength = selector.length;
int mid = 0;
char[] midSelector;
while (left <= right) {
mid = left + (right - left) /2;
int compare = compare(selector, midSelector = sortedMethods[mid].selector, selectorLength, midSelector.length);
if (compare < 0) {
right = mid-1;
} else if (compare > 0) {
left = mid+1;
} else {
int start = mid, end = mid;
// find first method with same selector
while (start > left && CharOperation.equals(sortedMethods[start-1].selector, selector)){ start--; }
// find last method with same selector
while (end < right && CharOperation.equals(sortedMethods[end+1].selector, selector)){ end++; }
return start + ((long)end<< 32);
}
}
return -1;
}
/**
* Compares two strings lexicographically.
* The comparison is based on the Unicode value of each character in
* the strings.
*
* @return the value <code>0</code> if the str1 is equal to str2;
* a value less than <code>0</code> if str1
* is lexicographically less than str2;
* and a value greater than <code>0</code> if str1 is
* lexicographically greater than str2.
*/
static int compare(char[] str1, char[] str2, int len1, int len2) {
int n= Math.min(len1, len2);
int i= 0;
while (n-- != 0) {
char c1= str1[i];
char c2= str2[i++];
if (c1 != c2) {
return c1 - c2;
}
}
return len1 - len2;
}
/**
* Sort the field array using a quicksort
*/
public static void sortFields(FieldBinding[] sortedFields, int left, int right) {
Arrays.sort(sortedFields, left, right, FIELD_COMPARATOR);
}
/**
* Sort the field array using a quicksort
*/
public static void sortMethods(MethodBinding[] sortedMethods, int left, int right) {
Arrays.sort(sortedMethods, left, right, METHOD_COMPARATOR);
}
//{ObjectTeams: some subclasses share an existing model
protected ReferenceBinding(TypeModel model) {
this.model = model;
if (model != null && model.getBinding() == null)
model.setBinding(this);
}
// SH}
// {ObjectTeams: new API for adding elements:
/**
* add a generated method
* @param method
*/
public void addMethod(MethodBinding method) {
throw new InternalCompilerError("Method not applicable on this type"); //$NON-NLS-1$
}
// SH}
/**
* Sort the member types using a quicksort
*/
static void sortMemberTypes(ReferenceBinding[] sortedMemberTypes, int left, int right) {
/*{ObjectTeams: completely disable name-based membertype sorting:
Arrays.sort(sortedMemberTypes, left, right, BASIC_MEMBER_TYPES_COMPARATOR);
SH}*/
}
/**
* Compares two reference bindings by the value of the {@link #sourceName} field.
* A ReferenceBinding with a sourceName field that has the value null is considered
* to be smaller than a ReferenceBinding that does have a source name.
*/
static final Comparator<ReferenceBinding> BASIC_MEMBER_TYPES_COMPARATOR = (ReferenceBinding o1, ReferenceBinding o2) -> {
char[] n1 = o1.sourceName;
char[] n2 = o2.sourceName;
// n1 or n2 may be null - compare without accessing the length of the array
if (n1 == null) {
if (n2 == null) {
return 0;
}
return -1;
} else if (n2 == null) {
return 1;
}
return ReferenceBinding.compare(n1, n2, n1.length, n2.length);
};
/**
* Return the array of resolvable fields (resilience)
*/
public FieldBinding[] availableFields() {
return fields();
}
/**
* Return the array of resolvable methods (resilience)
*/
public MethodBinding[] availableMethods() {
//{ObjectTeams: clients should see some generated methods, too:
try {
if (isRole())
Dependencies.ensureBindingState(this, ITranslationStates.STATE_METHODS_CREATED);
} catch (Throwable t) { /* don't care about exceptions in compiler */ }
// SH}
return methods();
}
public boolean hasHierarchyCheckStarted() {
return (this.tagBits & TagBits.BeginHierarchyCheck) != 0;
}
public void setHierarchyCheckDone() {
return;
}
/**
* Answer true if the receiver can be instantiated
*/
@Override
public boolean canBeInstantiated() {
return (this.modifiers & (ClassFileConstants.AccAbstract | ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation)) == 0;
}
/**
* Answer true if the receiver is visible to the invocationPackage.
*/
public boolean canBeSeenBy(PackageBinding invocationPackage) {
if (isPublic()) return true;
if (isPrivate()) return false;
// isProtected() or isDefault()
return invocationPackage == this.fPackage;
}
/**
* Answer true if the receiver is visible to the receiverType and the invocationType.
*/
public boolean canBeSeenBy(ReferenceBinding receiverType, ReferenceBinding invocationType) {
if (isPublic()) return true;
if (isStatic() && (receiverType.isRawType() || receiverType.isParameterizedType()))
receiverType = receiverType.actualType(); // outer generics are irrelevant
if (TypeBinding.equalsEquals(invocationType, this) && TypeBinding.equalsEquals(invocationType, receiverType)) return true;
if (isProtected()) {
// answer true if the invocationType is the declaringClass or they are in the same package
// OR the invocationType is a subclass of the declaringClass
// AND the invocationType is the invocationType or its subclass
// OR the type is a static method accessed directly through a type
// OR previous assertions are true for one of the enclosing type
if (TypeBinding.equalsEquals(invocationType, this)) return true;
if (invocationType.fPackage == this.fPackage) return true;
TypeBinding currentType = invocationType.erasure();
TypeBinding declaringClass = enclosingType().erasure(); // protected types always have an enclosing one
if (TypeBinding.equalsEquals(declaringClass, invocationType)) return true;
if (declaringClass == null) return false; // could be null if incorrect top-level protected type
//int depth = 0;
do {
if (currentType.findSuperTypeOriginatingFrom(declaringClass) != null) return true;
//depth++;
currentType = currentType.enclosingType();
} while (currentType != null);
return false;
}
if (isPrivate()) {
// answer true if the receiverType is the receiver or its enclosingType
// AND the invocationType and the receiver have a common enclosingType
receiverCheck: {
if (!(TypeBinding.equalsEquals(receiverType, this) || TypeBinding.equalsEquals(receiverType, enclosingType()))) {
// special tolerance for type variable direct bounds, but only if compliance <= 1.6, see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=334622
if (receiverType.isTypeVariable()) {
TypeVariableBinding typeVariable = (TypeVariableBinding) receiverType;
if (typeVariable.environment.globalOptions.complianceLevel <= ClassFileConstants.JDK1_6 && (typeVariable.isErasureBoundTo(erasure()) || typeVariable.isErasureBoundTo(enclosingType().erasure())))
break receiverCheck;
}
return false;
}
}
if (TypeBinding.notEquals(invocationType, this)) {
ReferenceBinding outerInvocationType = invocationType;
ReferenceBinding temp = outerInvocationType.enclosingType();
while (temp != null) {
outerInvocationType = temp;
temp = temp.enclosingType();
}
ReferenceBinding outerDeclaringClass = (ReferenceBinding)erasure();
temp = outerDeclaringClass.enclosingType();
while (temp != null) {
outerDeclaringClass = temp;
temp = temp.enclosingType();
}
if (TypeBinding.notEquals(outerInvocationType, outerDeclaringClass)) return false;
}
return true;
}
// isDefault()
if (invocationType.fPackage != this.fPackage) return false;
ReferenceBinding currentType = receiverType;
TypeBinding originalDeclaringClass = (enclosingType() == null ? this : enclosingType()).original();
do {
if (currentType.isCapture()) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=285002
if (TypeBinding.equalsEquals(originalDeclaringClass, currentType.erasure().original())) return true;
} else {
if (TypeBinding.equalsEquals(originalDeclaringClass, currentType.original())) return true;
}
PackageBinding currentPackage = currentType.fPackage;
// package could be null for wildcards/intersection types, ignore and recurse in superclass
if (currentPackage != null && currentPackage != this.fPackage) return false;
} while ((currentType = currentType.superclass()) != null);
return false;
}
/**
* Answer true if the receiver is visible to the type provided by the scope.
*/
@Override
public boolean canBeSeenBy(Scope scope) {
if (isPublic()) return true;
SourceTypeBinding invocationType = scope.enclosingSourceType();
if (TypeBinding.equalsEquals(invocationType, this)) return true;
if (invocationType == null) // static import call
return !isPrivate() && scope.getCurrentPackage() == this.fPackage;
if (isProtected()) {
// answer true if the invocationType is the declaringClass or they are in the same package
// OR the invocationType is a subclass of the declaringClass
// AND the invocationType is the invocationType or its subclass
// OR the type is a static method accessed directly through a type
// OR previous assertions are true for one of the enclosing type
if (invocationType.fPackage == this.fPackage) return true;
TypeBinding declaringClass = enclosingType(); // protected types always have an enclosing one
if (declaringClass == null) return false; // could be null if incorrect top-level protected type
declaringClass = declaringClass.erasure();// erasure cannot be null
TypeBinding currentType = invocationType.erasure();
// int depth = 0;
do {
if (TypeBinding.equalsEquals(declaringClass, invocationType)) return true;
if (currentType.findSuperTypeOriginatingFrom(declaringClass) != null) return true;
// depth++;
currentType = currentType.enclosingType();
} while (currentType != null);
return false;
}
if (isPrivate()) {
// answer true if the receiver and the invocationType have a common enclosingType
// already know they are not the identical type
ReferenceBinding outerInvocationType = invocationType;
ReferenceBinding temp = outerInvocationType.enclosingType();
while (temp != null) {
outerInvocationType = temp;
temp = temp.enclosingType();
}
ReferenceBinding outerDeclaringClass = (ReferenceBinding)erasure();
temp = outerDeclaringClass.enclosingType();
while (temp != null) {
outerDeclaringClass = temp;
temp = temp.enclosingType();
}
return TypeBinding.equalsEquals(outerInvocationType, outerDeclaringClass);
}
// isDefault()
return invocationType.fPackage == this.fPackage;
}
public char[] computeGenericTypeSignature(TypeVariableBinding[] typeVariables) {
boolean isMemberOfGeneric = isMemberType() && hasEnclosingInstanceContext() && (enclosingType().modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0;
if (typeVariables == Binding.NO_TYPE_VARIABLES && !isMemberOfGeneric) {
return signature();
}
StringBuffer sig = new StringBuffer(10);
if (isMemberOfGeneric) {
char[] typeSig = enclosingType().genericTypeSignature();
sig.append(typeSig, 0, typeSig.length-1); // copy all but trailing semicolon
sig.append('.'); // NOTE: cannot override trailing ';' with '.' in enclosing signature, since shared char[]
sig.append(this.sourceName);
} else {
char[] typeSig = signature();
sig.append(typeSig, 0, typeSig.length-1); // copy all but trailing semicolon
}
if (typeVariables == Binding.NO_TYPE_VARIABLES) {
sig.append(';');
} else {
sig.append('<');
for (int i = 0, length = typeVariables.length; i < length; i++) {
sig.append(typeVariables[i].genericTypeSignature());
}
sig.append(">;"); //$NON-NLS-1$
}
int sigLength = sig.length();
char[] result = new char[sigLength];
sig.getChars(0, sigLength, result, 0);
return result;
}
public void computeId() {
// note that more (configurable) ids are assigned from PackageBinding#checkIfNullAnnotationType()
// try to avoid multiple checks against a package/type name
switch (this.compoundName.length) {
case 3 :
//{ObjectTeams: org.objectteams...
if ( CharOperation.equals(IOTConstants.ORG, this.compoundName[0])
&& CharOperation.equals(IOTConstants.OBJECTTEAMS, this.compoundName[1]))
{
if(CharOperation.equals(IOTConstants.ITEAM, this.compoundName[2]))
this.id = IOTConstants.T_OrgObjectTeamsITeam;
else if(CharOperation.equals(IOTConstants.TEAM, this.compoundName[2]))
this.id = IOTConstants.T_OrgObjectTeamsTeam;
else if(CharOperation.equals(IOTConstants.IBOUNDBASE, this.compoundName[2]))
this.id = IOTConstants.T_OrgObjectTeamsIBoundBase;
else if(CharOperation.equals(IOTConstants.IBOUNDBASE2, this.compoundName[2]))
this.id = IOTConstants.T_OrgObjectTeamsIBoundBase2;
else if(CharOperation.equals(IOTConstants.INSTANTIATION, this.compoundName[2]))
this.id = IOTConstants.T_OrgObjectTeamsInstantiation;
return;
}
// SH}
char[] packageName = this.compoundName[0];
// expect only java.*.* and javax.*.* and junit.*.* and org.junit.*
switch (packageName.length) {
case 3: // only one type in this group, yet:
if (CharOperation.equals(TypeConstants.ORG_JUNIT_ASSERT, this.compoundName))
this.id = TypeIds.T_OrgJunitAssert;
return;
case 4:
if (!CharOperation.equals(TypeConstants.JAVA, packageName))
return;
break; // continue below ...
case 5:
switch (packageName[1]) {
case 'a':
if (CharOperation.equals(TypeConstants.JAVAX_ANNOTATION_INJECT_INJECT, this.compoundName))
this.id = TypeIds.T_JavaxInjectInject;
return;
case 'u':
if (CharOperation.equals(TypeConstants.JUNIT_FRAMEWORK_ASSERT, this.compoundName))
this.id = TypeIds.T_JunitFrameworkAssert;
return;
}
return;
default: return;
}
// ... at this point we know it's java.*.*
packageName = this.compoundName[1];
if (packageName.length == 0) return; // just to be safe
char[] typeName = this.compoundName[2];
if (typeName.length == 0) return; // just to be safe
// remaining types MUST be in java.*.*
if (!CharOperation.equals(TypeConstants.LANG, this.compoundName[1])) {
switch (packageName[0]) {
case 'i' :
if (CharOperation.equals(packageName, TypeConstants.IO)) {
switch (typeName[0]) {
case 'C' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_IO_CLOSEABLE[2]))
this.typeBits |= TypeIds.BitCloseable; // don't assign id, only typeBit (for analysis of resource leaks)
return;
case 'E' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_IO_EXTERNALIZABLE[2]))
this.id = TypeIds.T_JavaIoExternalizable;
return;
case 'I' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_IO_IOEXCEPTION[2]))
this.id = TypeIds.T_JavaIoException;
return;
case 'O' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_IO_OBJECTSTREAMEXCEPTION[2]))
this.id = TypeIds.T_JavaIoObjectStreamException;
return;
case 'P' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_IO_PRINTSTREAM[2]))
this.id = TypeIds.T_JavaIoPrintStream;
return;
case 'S' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_IO_SERIALIZABLE[2]))
this.id = TypeIds.T_JavaIoSerializable;
return;
}
}
return;
case 'u' :
if (CharOperation.equals(packageName, TypeConstants.UTIL)) {
switch (typeName[0]) {
case 'C' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_UTIL_COLLECTION[2])) {
this.id = TypeIds.T_JavaUtilCollection;
this.typeBits |= TypeIds.BitCollection;
}
return;
case 'I' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_UTIL_ITERATOR[2]))
this.id = TypeIds.T_JavaUtilIterator;
return;
case 'L' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_UTIL_LIST[2])) {
this.id = TypeIds.T_JavaUtilList;
this.typeBits |= TypeIds.BitList;
}
return;
case 'M' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_UTIL_MAP[2])) {
this.id = TypeIds.T_JavaUtilMap;
this.typeBits |= TypeIds.BitMap;
}
return;
case 'O' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_UTIL_OBJECTS[2]))
this.id = TypeIds.T_JavaUtilObjects;
return;
}
}
return;
}
return;
}
// remaining types MUST be in java.lang.*
switch (typeName[0]) {
case 'A' :
switch(typeName.length) {
case 13 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_AUTOCLOSEABLE[2])) {
this.id = TypeIds.T_JavaLangAutoCloseable;
this.typeBits |= TypeIds.BitAutoCloseable;
}
return;
case 14:
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ASSERTIONERROR[2]))
this.id = TypeIds.T_JavaLangAssertionError;
return;
}
return;
case 'B' :
switch (typeName.length) {
case 4 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_BYTE[2]))
this.id = TypeIds.T_JavaLangByte;
return;
case 7 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_BOOLEAN[2]))
this.id = TypeIds.T_JavaLangBoolean;
return;
}
return;
case 'C' :
switch (typeName.length) {
case 5 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_CLASS[2]))
this.id = TypeIds.T_JavaLangClass;
return;
case 9 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_CHARACTER[2]))
this.id = TypeIds.T_JavaLangCharacter;
else if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_CLONEABLE[2]))
this.id = TypeIds.T_JavaLangCloneable;
return;
case 22 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_CLASSNOTFOUNDEXCEPTION[2]))
this.id = TypeIds.T_JavaLangClassNotFoundException;
return;
}
return;
case 'D' :
switch (typeName.length) {
case 6 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_DOUBLE[2]))
this.id = TypeIds.T_JavaLangDouble;
return;
case 10 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_DEPRECATED[2]))
this.id = TypeIds.T_JavaLangDeprecated;
return;
}
return;
case 'E' :
switch (typeName.length) {
case 4 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ENUM[2]))
this.id = TypeIds.T_JavaLangEnum;
return;
case 5 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ERROR[2]))
this.id = TypeIds.T_JavaLangError;
return;
case 9 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_EXCEPTION[2]))
this.id = TypeIds.T_JavaLangException;
return;
}
return;
case 'F' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_FLOAT[2]))
this.id = TypeIds.T_JavaLangFloat;
else if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_FUNCTIONAL_INTERFACE[2]))
this.id = TypeIds.T_JavaLangFunctionalInterface;
return;
case 'I' :
switch (typeName.length) {
case 7 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_INTEGER[2]))
this.id = TypeIds.T_JavaLangInteger;
return;
case 8 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ITERABLE[2]))
this.id = TypeIds.T_JavaLangIterable;
return;
case 24 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ILLEGALARGUMENTEXCEPTION[2]))
this.id = TypeIds.T_JavaLangIllegalArgumentException;
return;
}
return;
case 'L' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_LONG[2]))
this.id = TypeIds.T_JavaLangLong;
return;
case 'N' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_NOCLASSDEFERROR[2]))
this.id = TypeIds.T_JavaLangNoClassDefError;
return;
case 'O' :
switch (typeName.length) {
case 6 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_OBJECT[2]))
this.id = TypeIds.T_JavaLangObject;
return;
case 8 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_OVERRIDE[2]))
this.id = TypeIds.T_JavaLangOverride;
return;
}
return;
case 'R' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION[2]))
this.id = TypeIds.T_JavaLangRuntimeException;
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_RECORD[2]))
this.id = TypeIds.T_JavaLangRecord;
break;
case 'S' :
switch (typeName.length) {
case 5 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_SHORT[2]))
this.id = TypeIds.T_JavaLangShort;
return;
case 6 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_STRING[2]))
this.id = TypeIds.T_JavaLangString;
else if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_SYSTEM[2]))
this.id = TypeIds.T_JavaLangSystem;
return;
case 11 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_SAFEVARARGS[2]))
this.id = TypeIds.T_JavaLangSafeVarargs;
return;
case 12 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_STRINGBUFFER[2]))
this.id = TypeIds.T_JavaLangStringBuffer;
return;
case 13 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_STRINGBUILDER[2]))
this.id = TypeIds.T_JavaLangStringBuilder;
return;
case 16 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_SUPPRESSWARNINGS[2]))
this.id = TypeIds.T_JavaLangSuppressWarnings;
return;
}
return;
case 'T' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_THROWABLE[2]))
this.id = TypeIds.T_JavaLangThrowable;
return;
case 'V' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_VOID[2]))
this.id = TypeIds.T_JavaLangVoid;
return;
}
break;
case 4:
// expect one type from com.*.*.*:
if (CharOperation.equals(TypeConstants.COM_GOOGLE_INJECT_INJECT, this.compoundName)) {
this.id = TypeIds.T_ComGoogleInjectInject;
return;
}
// otherwise only expect java.*.*.*
if (!CharOperation.equals(TypeConstants.JAVA, this.compoundName[0]))
return;
packageName = this.compoundName[1];
if (packageName.length == 0) return; // just to be safe
packageName = this.compoundName[2];
if (packageName.length == 0) return; // just to be safe
typeName = this.compoundName[3];
if (typeName.length == 0) return; // just to be safe
switch (packageName[0]) {
case 'a' :
if (CharOperation.equals(packageName, TypeConstants.ANNOTATION)) {
switch (typeName[0]) {
case 'A' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ANNOTATION_ANNOTATION[3]))
this.id = TypeIds.T_JavaLangAnnotationAnnotation;
return;
case 'D' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ANNOTATION_DOCUMENTED[3]))
this.id = TypeIds.T_JavaLangAnnotationDocumented;
return;
case 'E' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE[3]))
this.id = TypeIds.T_JavaLangAnnotationElementType;
return;
case 'I' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ANNOTATION_INHERITED[3]))
this.id = TypeIds.T_JavaLangAnnotationInherited;
return;
case 'R' :
switch (typeName.length) {
case 9 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ANNOTATION_RETENTION[3]))
this.id = TypeIds.T_JavaLangAnnotationRetention;
return;
case 10 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ANNOTATION_REPEATABLE[3]))
this.id = TypeIds.T_JavaLangAnnotationRepeatable;
return;
case 15 :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ANNOTATION_RETENTIONPOLICY[3]))
this.id = TypeIds.T_JavaLangAnnotationRetentionPolicy;
return;
}
return;
case 'T' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ANNOTATION_TARGET[3]))
this.id = TypeIds.T_JavaLangAnnotationTarget;
return;
}
}
return;
case 'i':
if (CharOperation.equals(packageName, TypeConstants.INVOKE)) {
if (typeName.length == 0) return; // just to be safe
switch (typeName[0]) {
case 'M' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_INVOKE_METHODHANDLE_$_POLYMORPHICSIGNATURE[3]))
this.id = TypeIds.T_JavaLangInvokeMethodHandlePolymorphicSignature;
return;
}
}
return;
case 'r' :
if (CharOperation.equals(packageName, TypeConstants.REFLECT)) {
switch (typeName[0]) {
case 'C' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_REFLECT_CONSTRUCTOR[2]))
this.id = TypeIds.T_JavaLangReflectConstructor;
return;
case 'F' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_REFLECT_FIELD[2]))
this.id = TypeIds.T_JavaLangReflectField;
return;
case 'M' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_REFLECT_METHOD[2]))
this.id = TypeIds.T_JavaLangReflectMethod;
return;
}
}
return;
}
break;
case 5 :
packageName = this.compoundName[0];
switch (packageName[0]) {
case 'j' :
if (!CharOperation.equals(TypeConstants.JAVA, this.compoundName[0]))
return;
packageName = this.compoundName[1];
if (packageName.length == 0) return; // just to be safe
if (CharOperation.equals(TypeConstants.LANG, packageName)) {
packageName = this.compoundName[2];
if (packageName.length == 0) return; // just to be safe
switch (packageName[0]) {
case 'i' :
if (CharOperation.equals(packageName, TypeConstants.INVOKE)) {
typeName = this.compoundName[3];
if (typeName.length == 0) return; // just to be safe
switch (typeName[0]) {
case 'M' :
char[] memberTypeName = this.compoundName[4];
if (memberTypeName.length == 0) return; // just to be safe
if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_INVOKE_METHODHANDLE_POLYMORPHICSIGNATURE[3])
&& CharOperation.equals(memberTypeName, TypeConstants.JAVA_LANG_INVOKE_METHODHANDLE_POLYMORPHICSIGNATURE[4]))
this.id = TypeIds.T_JavaLangInvokeMethodHandlePolymorphicSignature;
return;
}
}
return;
}
return;
}
return;
case 'o':
if (!CharOperation.equals(TypeConstants.ORG, this.compoundName[0]))
return;
packageName = this.compoundName[1];
if (packageName.length == 0) return; // just to be safe
switch (packageName[0]) {
case 'e':
if (CharOperation.equals(TypeConstants.ECLIPSE, packageName)) {
packageName = this.compoundName[2];
if (packageName.length == 0) return; // just to be safe
switch (packageName[0]) {
case 'c' :
if (CharOperation.equals(packageName, TypeConstants.CORE)) {
typeName = this.compoundName[3];
if (typeName.length == 0) return; // just to be safe
switch (typeName[0]) {
case 'r' :
char[] memberTypeName = this.compoundName[4];
if (memberTypeName.length == 0) return; // just to be safe
if (CharOperation.equals(typeName, TypeConstants.ORG_ECLIPSE_CORE_RUNTIME_ASSERT[3])
&& CharOperation.equals(memberTypeName, TypeConstants.ORG_ECLIPSE_CORE_RUNTIME_ASSERT[4]))
this.id = TypeIds.T_OrgEclipseCoreRuntimeAssert;
return;
}
}
return;
}
return;
}
return;
case 'a':
if (CharOperation.equals(TypeConstants.APACHE, packageName)) {
if (CharOperation.equals(TypeConstants.COMMONS, this.compoundName[2])) {
if (CharOperation.equals(TypeConstants.ORG_APACHE_COMMONS_LANG_VALIDATE, this.compoundName))
this.id = TypeIds.T_OrgApacheCommonsLangValidate;
else if (CharOperation.equals(TypeConstants.ORG_APACHE_COMMONS_LANG3_VALIDATE, this.compoundName))
this.id = TypeIds.T_OrgApacheCommonsLang3Validate;
}
}
return;
}
return;
case 'c':
if (!CharOperation.equals(TypeConstants.COM, this.compoundName[0]))
return;
if (CharOperation.equals(TypeConstants.COM_GOOGLE_COMMON_BASE_PRECONDITIONS, this.compoundName))
this.id = TypeIds.T_ComGoogleCommonBasePreconditions;
return;
}
break;
case 6:
if (CharOperation.equals(TypeConstants.ORG, this.compoundName[0])) {
if (CharOperation.equals(TypeConstants.SPRING, this.compoundName[1])) {
if (CharOperation.equals(TypeConstants.AUTOWIRED, this.compoundName[5])) {
if (CharOperation.equals(TypeConstants.ORG_SPRING_AUTOWIRED, this.compoundName)) {
this.id = TypeIds.T_OrgSpringframeworkBeansFactoryAnnotationAutowired;
}
}
return;
}
if (CharOperation.equals(TypeConstants.JUNIT, this.compoundName[1])) {
if (CharOperation.equals(TypeConstants.METHOD_SOURCE, this.compoundName[5])) {
if (CharOperation.equals(TypeConstants.ORG_JUNIT_METHOD_SOURCE, this.compoundName)) {
this.id = TypeIds.T_OrgJunitJupiterParamsProviderMethodSource;
}
}
return;
}
if (!CharOperation.equals(TypeConstants.JDT, this.compoundName[2]) || !CharOperation.equals(TypeConstants.ITYPEBINDING, this.compoundName[5]))
return;
if (CharOperation.equals(TypeConstants.ORG_ECLIPSE_JDT_CORE_DOM_ITYPEBINDING, this.compoundName))
this.typeBits |= TypeIds.BitUninternedType;
}
break;
case 7 :
if (!CharOperation.equals(TypeConstants.JDT, this.compoundName[2]) || !CharOperation.equals(TypeConstants.TYPEBINDING, this.compoundName[6]))
return;
if (CharOperation.equals(TypeConstants.ORG_ECLIPSE_JDT_INTERNAL_COMPILER_LOOKUP_TYPEBINDING, this.compoundName))
this.typeBits |= TypeIds.BitUninternedType;
break;
}
}
public void computeId(LookupEnvironment environment) {
environment.getUnannotatedType(this);
}
/**
* p.X<T extends Y & I, U extends Y> {} -> Lp/X<TT;TU;>;
*/
@Override
public char[] computeUniqueKey(boolean isLeaf) {
if (!isLeaf) return signature();
return genericTypeSignature();
}
/**
* Answer the receiver's constant pool name.
*
* NOTE: This method should only be used during/after code gen.
*/
@Override
public char[] constantPoolName() /* java/lang/Object */ {
if (this.constantPoolName != null) return this.constantPoolName;
return this.constantPoolName = CharOperation.concatWith(this.compoundName, '/');
}
//{ObjectTeams: this is how type names are encoded in OT byte code attributes
public char[] attributeName() /* p1.p2.COuter$CInner */ {
return CharOperation.concatWith(this.compoundName, '.');
}
// SH}
@Override
public String debugName() {
return (this.compoundName != null) ? this.hasTypeAnnotations() ? annotatedDebugName() : new String(readableName()) : "UNNAMED TYPE"; //$NON-NLS-1$
}
@Override
public int depth() {
int depth = 0;
ReferenceBinding current = this;
while ((current = current.enclosingType()) != null)
depth++;
return depth;
}
public boolean detectAnnotationCycle() {
if ((this.tagBits & TagBits.EndAnnotationCheck) != 0) return false; // already checked
if ((this.tagBits & TagBits.BeginAnnotationCheck) != 0) return true; // in the middle of checking its methods
this.tagBits |= TagBits.BeginAnnotationCheck;
MethodBinding[] currentMethods = methods();
boolean inCycle = false; // check each method before failing
for (int i = 0, l = currentMethods.length; i < l; i++) {
TypeBinding returnType = currentMethods[i].returnType.leafComponentType().erasure();
if (TypeBinding.equalsEquals(this, returnType)) {
if (this instanceof SourceTypeBinding) {
MethodDeclaration decl = (MethodDeclaration) currentMethods[i].sourceMethod();
((SourceTypeBinding) this).scope.problemReporter().annotationCircularity(this, this, decl != null ? decl.returnType : null);
}
} else if (returnType.isAnnotationType() && ((ReferenceBinding) returnType).detectAnnotationCycle()) {
if (this instanceof SourceTypeBinding) {
MethodDeclaration decl = (MethodDeclaration) currentMethods[i].sourceMethod();
((SourceTypeBinding) this).scope.problemReporter().annotationCircularity(this, returnType, decl != null ? decl.returnType : null);
}
inCycle = true;
}
}
if (inCycle)
return true;
this.tagBits |= TagBits.EndAnnotationCheck;
return false;
}
public final ReferenceBinding enclosingTypeAt(int relativeDepth) {
ReferenceBinding current = this;
while (relativeDepth-- > 0 && current != null)
current = current.enclosingType();
return current;
}
public int enumConstantCount() {
int count = 0;
FieldBinding[] fields = fields();
for (int i = 0, length = fields.length; i < length; i++) {
if ((fields[i].modifiers & ClassFileConstants.AccEnum) != 0) count++;
}
return count;
}
public int fieldCount() {
//{ObjectTeams: don't count faked base field:
if (isRole()) {
int count = 0;
for (FieldBinding field : fields()) {
if ((field.otBits & IOTConstants.IsFakedField) ==0)
count++;
}
return count;
}
// SH}
return fields().length;
}
public FieldBinding[] fields() {
return Binding.NO_FIELDS;
}
public final int getAccessFlags() {
//{ObjectTeams: use extended mask (was AccJustFlag):
return this.modifiers & ExtraCompilerModifiers.AccOTTypeJustFlag;
// SH}
}
/**
* @return the JSR 175 annotations for this type.
*/
@Override
public AnnotationBinding[] getAnnotations() {
return retrieveAnnotations(this);
}
/**
* @see org.eclipse.jdt.internal.compiler.lookup.Binding#getAnnotationTagBits()
*/
@Override
public long getAnnotationTagBits() {
return this.tagBits;
}
/**
* @return the enclosingInstancesSlotSize
*/
public int getEnclosingInstancesSlotSize() {
if (isStatic()) return 0;
return enclosingType() == null ? 0 : 1;
}
public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
return null;
}
public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes, CompilationUnitScope refScope) {
return null;
}
public FieldBinding getField(char[] fieldName, boolean needResolve) {
return null;
}
/**
* @see org.eclipse.jdt.internal.compiler.env.IDependent#getFileName()
*/
public char[] getFileName() {
return this.fileName;
}
/**
* Find the member type with the given simple typeName. Benefits from the fact that
* the array of {@link #memberTypes()} is sorted.
*/
public ReferenceBinding getMemberType(char[] typeName) {
ReferenceBinding[] memberTypes = memberTypes();
//{ObjectTeams: restore old linear lookup:
for (int i = memberTypes.length; --i >= 0;)
if (CharOperation.equals(memberTypes[i].sourceName, typeName))
return memberTypes[i];
/* orig: 4.13M1
int memberTypeIndex = binarySearch(typeName, memberTypes);
if (memberTypeIndex >= 0) {
return memberTypes[memberTypeIndex];
}
:giro */
// SH}
return null;
}
//{ObjectTeams: new utility function
public ReferenceBinding getMemberTypeRecurse(char[] typeName) {
ReferenceBinding[] memberTypes = memberTypes();
for (int i = memberTypes.length; --i >= 0;) {
if (CharOperation.equals(memberTypes[i].sourceName, typeName))
return memberTypes[i];
ReferenceBinding result = memberTypes[i].getMemberTypeRecurse(typeName);
if (result != null)
return result;
}
return null;
}
// SH}
/**
* Search the given sourceName in the list of sorted member types.
*
* Neither the array of sortedMemberTypes nor the given sourceName may be null.
*/
static int binarySearch(char[] sourceName, ReferenceBinding[] sortedMemberTypes) {
if (sortedMemberTypes == null)
return -1;
int max = sortedMemberTypes.length, nameLength = sourceName.length;
if (max == 0)
return -1;
int left = 0, right = max - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
char[] midName = sortedMemberTypes[mid].sourceName;
// The read source name may be null. In that case, the given sourceName is considered
// to be larger than the current value at mid.
int compare = midName == null ? 1 : compare(sourceName, midName, nameLength, midName.length);
if (compare < 0) {
right = mid-1;
} else if (compare > 0) {
left = mid+1;
} else {
return mid;
}
}
return -1;
}
@Override
public MethodBinding[] getMethods(char[] selector) {
return Binding.NO_METHODS;
}
//Answer methods named selector, which take no more than the suggestedParameterLength.
//The suggested parameter length is optional and may not be guaranteed by every type.
public MethodBinding[] getMethods(char[] selector, int suggestedParameterLength) {
return getMethods(selector);
}
//{ObjectTeams:
/**
* get method by its selector, search includes superclasses, superinterfaces
* (except when searching a constructor).
* If more than one method (significantly, ie., not overriding each other)
* is found, return a ProblemMethodBinding, if none is found return null.
* Ignore tsuper versions of methods.
*/
public MethodBinding getMethod(Scope scope, char[] selector) {
MethodBinding[] currentMethods = getMethods(selector);
MethodBinding foundMethod = null;
if (currentMethods != null)
{
int numFound = currentMethods.length;
int suitableIdx = 0;
for (int i=0; i<currentMethods.length; i++) {
if (TSuperHelper.isTSuper(currentMethods[i]))
numFound--;
else
suitableIdx = i;
}
if (numFound == 1)
foundMethod = currentMethods[suitableIdx];
else if (numFound > 1)
return new ProblemMethodBinding(selector, Binding.NO_PARAMETERS, ProblemReasons.Ambiguous);
}
if (CharOperation.equals(TypeConstants.INIT, selector))
return foundMethod; // don't search supers for constructor
MethodVerifier verifier = scope.environment().methodVerifier(); // respect source level.
if (superclass() != null) {
MethodBinding superclassMethod = superclass().getMethod(scope, selector);
foundMethod = combineFoundMethods(foundMethod, superclassMethod, verifier);
}
if (foundMethod != null && !foundMethod.isValidBinding())
return foundMethod; // one problem is enough
ReferenceBinding[] superInterfaces = superInterfaces();
if (superInterfaces != null) {
for (int i = 0; i < superInterfaces.length; i++) {
MethodBinding superIfcMethod = superInterfaces[i].getMethod(scope, selector);
foundMethod = combineFoundMethods(foundMethod, superIfcMethod, verifier);
if (foundMethod != null && !foundMethod.isValidBinding())
return foundMethod; // one problem is enough
}
}
return foundMethod;
}
/**
* helper for the above
* @param match1
* @param superMethod
* @param verifier
* @return either match1 or superMethod or a ProblemMethodBinding (Ambiguous)
*/
private MethodBinding combineFoundMethods(
MethodBinding match1,
MethodBinding superMethod,
MethodVerifier verifier)
{
MethodBinding foundMethod = match1;
if (superMethod != null)
{
if (superMethod.isPrivate())
return match1; // ignore private method
if (!superMethod.isValidBinding()) {
foundMethod = superMethod; // propagate problem
} else {
if (match1 == null) {
foundMethod = superMethod;
} else {
MethodBinding superSubstitute= verifier.computeSubstituteMethod(superMethod, match1);
if (superSubstitute != null)
superMethod= superSubstitute;
if (!ImplicitNullAnnotationVerifier.areParametersEqual(match1, superMethod, verifier.environment))
foundMethod = new ProblemMethodBinding(match1.selector, Binding.NO_PARAMETERS, ProblemReasons.Ambiguous);
}
}
}
return foundMethod;
}
// SH}
/**
* @return the outerLocalVariablesSlotSize
*/
public int getOuterLocalVariablesSlotSize() {
return 0;
}
@Override
public PackageBinding getPackage() {
return this.fPackage;
}
public TypeVariableBinding getTypeVariable(char[] variableName) {
TypeVariableBinding[] typeVariables = typeVariables();
for (int i = typeVariables.length; --i >= 0;)
if (CharOperation.equals(typeVariables[i].sourceName, variableName))
return typeVariables[i];
return null;
}
@Override
public int hashCode() {
// ensure ReferenceBindings hash to the same position as UnresolvedReferenceBindings so they can be replaced without rehashing
// ALL ReferenceBindings are unique when created so equals() is the same as ==
return (this.compoundName == null || this.compoundName.length == 0)
? super.hashCode()
: CharOperation.hashCode(this.compoundName[this.compoundName.length - 1]);
}
final int identityHashCode() {
return super.hashCode();
}
/**
* Returns true if the two types have an incompatible common supertype,
* e.g. List<String> and List<Integer>
*/
public boolean hasIncompatibleSuperType(ReferenceBinding otherType) {
if (TypeBinding.equalsEquals(this, otherType)) return false;
ReferenceBinding[] interfacesToVisit = null;
int nextPosition = 0;
ReferenceBinding currentType = this;
TypeBinding match;
do {
match = otherType.findSuperTypeOriginatingFrom(currentType);
if (match != null && match.isProvablyDistinct(currentType))
return true;
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 (TypeBinding.equalsEquals(currentType, otherType)) return false;
match = otherType.findSuperTypeOriginatingFrom(currentType);
if (match != null && match.isProvablyDistinct(currentType))
return true;
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 false;
}
public boolean hasMemberTypes() {
return false;
}
/**
* Answer whether a @NonNullByDefault is applicable at the reference binding,
* for 1.8 check if the default is applicable to the given kind of location.
*/
// pre: null annotation analysis is enabled
boolean hasNonNullDefaultFor(int location, int sourceStart) {
// Note, STB overrides for correctly handling local types
ReferenceBinding currentType = this;
while (currentType != null) {
int nullDefault = ((ReferenceBinding)currentType.original()).getNullDefault();
if (nullDefault != 0)
return (nullDefault & location) != 0;
currentType = currentType.enclosingType();
}
// package
return (this.getPackage().getDefaultNullness() & location) != 0;
}
int getNullDefault() {
return 0;
}
@Override
public boolean acceptsNonNullDefault() {
return true;
}
public final boolean hasRestrictedAccess() {
return (this.modifiers & ExtraCompilerModifiers.AccRestrictedAccess) != 0;
}
/** Query typeBits without triggering supertype lookup. */
public boolean hasNullBit(int mask) {
return (this.typeBits & mask) != 0;
}
//{ObjectTeams: support asymmetric comparison. // FIXME(SH): is this needed or is super-impl smart enough??
@Override
public boolean isProvablyDistinct(TypeBinding otherType) {
if (otherType.isRoleType())
return otherType.isProvablyDistinct(this);
else
return super.isProvablyDistinct(otherType);
}
// SH}
/** Answer true if the receiver implements anInterface or is identical to anInterface.
* If searchHierarchy is true, then also search the receiver's superclasses.
*
* NOTE: Assume that anInterface is an interface.
*/
public boolean implementsInterface(ReferenceBinding anInterface, boolean searchHierarchy) {
if (TypeBinding.equalsEquals(this, anInterface))
return true;
ReferenceBinding[] interfacesToVisit = null;
int nextPosition = 0;
ReferenceBinding currentType = this;
do {
ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) { // in code assist cases when source types are added late, may not be finished connecting hierarchy
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 (searchHierarchy && (currentType = currentType.superclass()) != null);
for (int i = 0; i < nextPosition; i++) {
currentType = interfacesToVisit[i];
if (currentType.isEquivalentTo(anInterface))
return true;
ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) { // in code assist cases when source types are added late, may not be finished connecting hierarchy
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;
}
}
}
//{ObjectTeams: special case: bound base classes are conform to o.o.IBoundBase:
if (isBoundBase())
return (anInterface.id == IOTConstants.T_OrgObjectTeamsIBoundBase
|| anInterface.id == IOTConstants.T_OrgObjectTeamsIBoundBase2); // assume only one of these can be used during one compile
//SH}
return false;
}
// Internal method... assume its only sent to classes NOT interfaces
//{ObjectTeams: accessible to sub-class:
@Override
protected
// SH}
boolean implementsMethod(MethodBinding method) {
char[] selector = method.selector;
ReferenceBinding type = this;
while (type != null) {
MethodBinding[] methods = type.methods();
long range;
if ((range = ReferenceBinding.binarySearch(selector, methods)) >= 0) {
int start = (int) range, end = (int) (range >> 32);
for (int i = start; i <= end; i++) {
if (methods[i].areParametersEqual(method))
return true;
}
}
type = type.superclass();
}
return false;
}
/**
* Answer true if the receiver is an abstract type
*/
public final boolean isAbstract() {
return (this.modifiers & ClassFileConstants.AccAbstract) != 0;
}
@Override
public boolean isAnnotationType() {
return (this.modifiers & ClassFileConstants.AccAnnotation) != 0;
}
@Override
public final boolean isBinaryBinding() {
return (this.tagBits & TagBits.IsBinaryBinding) != 0;
}
@Override
public boolean isClass() {
return (this.modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) == 0;
}
private static SourceTypeBinding getSourceTypeBinding(ReferenceBinding ref) {
if (ref instanceof SourceTypeBinding)
return (SourceTypeBinding) ref;
if (ref instanceof ParameterizedTypeBinding) {
ParameterizedTypeBinding ptb = (ParameterizedTypeBinding) ref;
return ptb.type instanceof SourceTypeBinding ? (SourceTypeBinding) ptb.type : null;
}
return null;
}
public boolean isNestmateOf(ReferenceBinding other) {
SourceTypeBinding s1 = getSourceTypeBinding(this);
SourceTypeBinding s2 = getSourceTypeBinding(other);
if (s1 == null || s2 == null) return false;
return s1.isNestmateOf(s2);
}
@Override
public boolean isProperType(boolean admitCapture18) {
ReferenceBinding outer = enclosingType();
if (outer != null && !outer.isProperType(admitCapture18))
return false;
return super.isProperType(admitCapture18);
}
//{ObjectTeams: more queries in preparition of RoleTypeBinding:
/**
* Overridden in RoleTypeBinding.
* @return the source type (even if we had a RoleTypeBinding).
*/
public ReferenceBinding getRealType() {
if (this.roleModel != null)
{
ReferenceBinding ifcPart = this.roleModel.getInterfacePartBinding();
if (ifcPart != null) {
if (isRawType() && !ifcPart.isRawType())
return (ReferenceBinding) ((ParameterizedTypeBinding)this).environment.convertToRawType(ifcPart, false);
return ifcPart;
}
}
return this;
}
/**
* Overridden in RoleTypeBinding.
* @return the class (even if we had a RoleTypeBinding).
*/
public ReferenceBinding getRealClass() {
if (this.roleModel != null)
{
ReferenceBinding classPart = this.roleModel.getClassPartBinding();
if (classPart != null)
return classPart;
}
return this;
}
/**
* Return a version of other that has the same type arguments as this.
*/
public ReferenceBinding transferTypeArguments(ReferenceBinding other) {
// only subclasses do real work
return other;
}
// SH}
/**
* Answer true if the receiver type can be assigned to the argument type (right)
* In addition to improving performance, caching also ensures there is no infinite regression
* since per nature, the compatibility check is recursive through parameterized type arguments (122775)
*/
@Override
public boolean isCompatibleWith(TypeBinding otherType, /*@Nullable*/ Scope captureScope) {
//{ObjectTeams: behind the facade introduce new parameter useObjectShortcut.
return isCompatibleWith(otherType, true, captureScope);
}
// version which does not consider everything conform to Object:
public boolean isStrictlyCompatibleWith(TypeBinding otherType, /*@Nullable*/ Scope captureScope) {
return isCompatibleWith(otherType, false, captureScope);
}
public boolean isCompatibleWith(TypeBinding otherType, boolean useObjectShortcut, /*@Nullable*/ Scope captureScope) {
// SH}
if (equalsEquals(otherType, this))
return true;
//{ObjectTeams: respect new argument useObjectShortcut:
/* orig:
if (otherType.id == TypeIds.T_JavaLangObject)
:giro */
if (otherType.id == TypeIds.T_JavaLangObject && useObjectShortcut)
// SH}
return true;
Object result;
if (this.compatibleCache == null) {
this.compatibleCache = new SimpleLookupTable(3);
result = null;
} else {
result = this.compatibleCache.get(otherType); // [dbg reset] this.compatibleCache.put(otherType,null)
if (result != null) {
return result == Boolean.TRUE;
}
}
this.compatibleCache.put(otherType, Boolean.FALSE); // protect from recursive call
//{ObjectTeams: propagate:
/* orig:
if (isCompatibleWith0(otherType, captureScope)) {
:giro */
if (isCompatibleWith0(otherType, useObjectShortcut, captureScope)) {
// SH}
this.compatibleCache.put(otherType, Boolean.TRUE);
return true;
}
if (captureScope == null
&& this instanceof TypeVariableBinding
&& ((TypeVariableBinding)this).firstBound instanceof ParameterizedTypeBinding) {
// see https://bugs.eclipse.org/395002#c9
// in this case a subsequent check with captureScope != null may actually get
// a better result, reset this info to ensure we're not blocking that re-check.
this.compatibleCache.put(otherType, null);
}
return false;
}
//{ObjectTeams: after re-wiring superclass/ifc reset all false values in the compatibleCache
public void resetIncompatibleTypes() {
if (this.compatibleCache == null) return;
for (int i=0; i< this.compatibleCache.valueTable.length; i++) {
if (this.compatibleCache.valueTable[i] == Boolean.FALSE) {
this.compatibleCache.keyTable[i] = null;
this.compatibleCache.elementSize--;
}
}
}
// SH}
/**
* Answer true if the receiver type can be assigned to the argument type (right)
*/
//{ObjectTeams: new parameter useObjectShortcut
private boolean isCompatibleWith0(TypeBinding otherType, boolean useObjectShortcut, /*@Nullable*/ Scope captureScope) {
// SH}
if (TypeBinding.equalsEquals(otherType, this))
return true;
//{ObjectTeams: respect new param:
/*orig:
if (otherType.id == TypeIds.T_JavaLangObject)
:giro*/
if (otherType.id == TypeIds.T_JavaLangObject && useObjectShortcut)
// SH}
return true;
// equivalence may allow compatibility with array type through wildcard
// bound
if (isEquivalentTo(otherType))
return true;
switch (otherType.kind()) {
case Binding.WILDCARD_TYPE :
case Binding.INTERSECTION_TYPE:
return false; // should have passed equivalence check above if
// wildcard
case Binding.TYPE_PARAMETER :
// check compatibility with capture of ? super X
if (otherType.isCapture()) {
CaptureBinding otherCapture = (CaptureBinding) otherType;
TypeBinding otherLowerBound;
if ((otherLowerBound = otherCapture.lowerBound) != null) {
if (otherLowerBound.isArrayType()) return false;
return isCompatibleWith(otherLowerBound);
}
}
if (otherType instanceof InferenceVariable) {
// may interpret InferenceVariable as a joker, but only when within an outer lambda inference:
if (captureScope != null) {
MethodScope methodScope = captureScope.methodScope();
if (methodScope != null) {
ReferenceContext referenceContext = methodScope.referenceContext;
if (referenceContext instanceof LambdaExpression
&& ((LambdaExpression)referenceContext).inferenceContext != null)
return true;
}
}
}
//$FALL-THROUGH$
case Binding.GENERIC_TYPE :
case Binding.TYPE :
case Binding.PARAMETERIZED_TYPE :
case Binding.RAW_TYPE :
case Binding.INTERSECTION_TYPE18 :
switch (kind()) {
case Binding.GENERIC_TYPE :
case Binding.PARAMETERIZED_TYPE :
case Binding.RAW_TYPE :
if (TypeBinding.equalsEquals(erasure(), otherType.erasure()))
return false; // should have passed equivalence check
// above if same erasure
}
ReferenceBinding otherReferenceType = (ReferenceBinding) otherType;
if (otherReferenceType.isIntersectionType18()) {
ReferenceBinding[] intersectingTypes = ((IntersectionTypeBinding18)otherReferenceType).intersectingTypes;
for (ReferenceBinding binding : intersectingTypes) {
if (!isCompatibleWith(binding))
return false;
}
return true;
}
if (otherReferenceType.isInterface()) { // could be annotation type
if (implementsInterface(otherReferenceType, true))
return true;
if (this instanceof TypeVariableBinding && captureScope != null) {
TypeVariableBinding typeVariable = (TypeVariableBinding) this;
if (typeVariable.firstBound instanceof ParameterizedTypeBinding) {
TypeBinding bound = typeVariable.firstBound.capture(captureScope, -1, -1); // no position needed as this capture will never escape this context
return bound.isCompatibleWith(otherReferenceType);
}
}
}
//{ObjectTeams: only leave if we have checked for java.lang.Object above:
/* orig:
if (isInterface()) // Explicit conversion from an interface
// to a class is not allowed
:giro */
if (isInterface() && useObjectShortcut)
// SH}
return false;
return otherReferenceType.isSuperclassOf(this);
default :
return false;
}
}
//{ObjectTeams: type weakening and lowering
public ReferenceBinding weakenFrom(ReferenceBinding other) {
return other;
}
public boolean isCompatibleViaLowering(ReferenceBinding other) {
return false;
}
// SH}
@Override
public boolean isSubtypeOf(TypeBinding other, boolean simulatingBugJDK8026527) {
if (isSubTypeOfRTL(other))
return true;
// TODO: if this has wildcards, perform capture before the next call:
TypeBinding candidate = findSuperTypeOriginatingFrom(other);
if (candidate == null)
return false;
if (TypeBinding.equalsEquals(candidate, other))
return true;
// T<Ai...> <: T#RAW:
if (other.isRawType() && TypeBinding.equalsEquals(candidate.erasure(), other.erasure()))
return true;
TypeBinding[] sis = other.typeArguments();
TypeBinding[] tis = candidate.typeArguments();
if (tis == null || sis == null)
return false;
if (sis.length != tis.length)
return false;
for (int i = 0; i < sis.length; i++) {
if (!tis[i].isTypeArgumentContainedBy(sis[i]))
return false;
}
return true;
}
protected boolean isSubTypeOfRTL(TypeBinding other) {
if (TypeBinding.equalsEquals(this, other))
return true;
if (other instanceof CaptureBinding) {
// for this one kind we must first unwrap the rhs:
TypeBinding lower = ((CaptureBinding) other).lowerBound;
return (lower != null && isSubtypeOf(lower, false));
}
if (other instanceof ReferenceBinding) {
TypeBinding[] intersecting = ((ReferenceBinding) other).getIntersectingTypes();
if (intersecting != null) {
for (int i = 0; i < intersecting.length; i++) {
if (!isSubtypeOf(intersecting[i], false))
return false;
}
return true;
}
}
return false;
}
/**
* Answer true if the receiver has default visibility
*/
public final boolean isDefault() {
return (this.modifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate)) == 0;
}
/**
* Answer true if the receiver is a deprecated type
*/
public final boolean isDeprecated() {
return (this.modifiers & ClassFileConstants.AccDeprecated) != 0;
}
@Override
public boolean isEnum() {
return (this.modifiers & ClassFileConstants.AccEnum) != 0;
}
/**
* Answer true if the receiver is final and cannot be subclassed
*/
public final boolean isFinal() {
return (this.modifiers & ClassFileConstants.AccFinal) != 0;
}
/**
* Returns true if the type hierarchy is being connected
*/
public boolean isHierarchyBeingConnected() {
return (this.tagBits & TagBits.EndHierarchyCheck) == 0 && (this.tagBits & TagBits.BeginHierarchyCheck) != 0;
}
/**
* Returns true if the type hierarchy is being connected "actively" i.e not paused momentatrily,
* while resolving type arguments. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=294057
*/
public boolean isHierarchyBeingActivelyConnected() {
return (this.tagBits & TagBits.EndHierarchyCheck) == 0 && (this.tagBits & TagBits.BeginHierarchyCheck) != 0 && (this.tagBits & TagBits.PauseHierarchyCheck) == 0;
}
/**
* Returns true if the type hierarchy is connected
*/
public boolean isHierarchyConnected() {
return true;
}
@Override
public boolean isInterface() {
// consider strict interfaces and annotation types
return (this.modifiers & ClassFileConstants.AccInterface) != 0;
}
@Override
public boolean isFunctionalInterface(Scope scope) {
MethodBinding method;
return isInterface() && (method = getSingleAbstractMethod(scope, true)) != null && method.isValidBinding();
}
/**
* Answer true if the receiver has private visibility
*/
public final boolean isPrivate() {
return (this.modifiers & ClassFileConstants.AccPrivate) != 0;
}
/**
* Answer true if the receiver or any of its enclosing types have private visibility
*/
public final boolean isOrEnclosedByPrivateType() {
if (isLocalType()) return true; // catch all local types
ReferenceBinding type = this;
while (type != null) {
if ((type.modifiers & ClassFileConstants.AccPrivate) != 0)
return true;
type = type.enclosingType();
}
return false;
}
/**
* Answer true if the receiver has protected visibility
*/
public final boolean isProtected() {
return (this.modifiers & ClassFileConstants.AccProtected) != 0;
}
/**
* Answer true if the receiver has public visibility
*/
public final boolean isPublic() {
return (this.modifiers & ClassFileConstants.AccPublic) != 0;
}
/**
* Answer true if the receiver is a static member type (or toplevel)
*/
@Override
public final boolean isStatic() {
//{ObjectTeams: roles, even their interface part, are not static:
if ((this.modifiers & ExtraCompilerModifiers.AccRole) != 0) return false;
// SH}
return (this.modifiers & (ClassFileConstants.AccStatic | ClassFileConstants.AccInterface)) != 0 || (this.tagBits & TagBits.IsNestedType) == 0;
}
/**
* Answer true if all float operations must adher to IEEE 754 float/double rules
*/
public final boolean isStrictfp() {
return (this.modifiers & ClassFileConstants.AccStrictfp) != 0;
}
/**
* Answer true if the receiver is in the superclass hierarchy of aType
* NOTE: Object.isSuperclassOf(Object) -> false
*/
public boolean isSuperclassOf(ReferenceBinding otherType) {
while ((otherType = otherType.superclass()) != null) {
if (otherType.isEquivalentTo(this)) return true;
}
return false;
}
/**
* @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#isThrowable()
*/
@Override
public boolean isThrowable() {
ReferenceBinding current = this;
do {
switch (current.id) {
case TypeIds.T_JavaLangThrowable :
case TypeIds.T_JavaLangError :
case TypeIds.T_JavaLangRuntimeException :
case TypeIds.T_JavaLangException :
return true;
}
} while ((current = current.superclass()) != null);
return false;
}
/**
* JLS 11.5 ensures that Throwable, Exception, RuntimeException and Error are directly connected.
* (Throwable<- Exception <- RumtimeException, Throwable <- Error). Thus no need to check #isCompatibleWith
* but rather check in type IDs so as to avoid some eager class loading for JCL writers.
* When 'includeSupertype' is true, answers true if the given type can be a supertype of some unchecked exception
* type (i.e. Throwable or Exception).
* @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#isUncheckedException(boolean)
*/
@Override
public boolean isUncheckedException(boolean includeSupertype) {
switch (this.id) {
case TypeIds.T_JavaLangError :
case TypeIds.T_JavaLangRuntimeException :
return true;
case TypeIds.T_JavaLangThrowable :
case TypeIds.T_JavaLangException :
return includeSupertype;
}
ReferenceBinding current = this;
while ((current = current.superclass()) != null) {
switch (current.id) {
case TypeIds.T_JavaLangError :
case TypeIds.T_JavaLangRuntimeException :
return true;
case TypeIds.T_JavaLangThrowable :
case TypeIds.T_JavaLangException :
return false;
}
}
return false;
}
/**
* Answer true if the receiver has private visibility and is used locally
*/
public final boolean isUsed() {
return (this.modifiers & ExtraCompilerModifiers.AccLocallyUsed) != 0;
}
/**
* Answer true if the receiver is deprecated (or any of its enclosing types)
*/
public final boolean isViewedAsDeprecated() {
if ((this.modifiers & (ClassFileConstants.AccDeprecated | ExtraCompilerModifiers.AccDeprecatedImplicitly)) != 0)
return true;
if (getPackage().isViewedAsDeprecated()) {
this.tagBits |= (getPackage().tagBits & TagBits.AnnotationTerminallyDeprecated);
return true;
}
return false;
}
/**
* Returns the member types of this type sorted by simple name.
*/
@Override
public ReferenceBinding[] memberTypes() {
return Binding.NO_MEMBER_TYPES;
}
public MethodBinding[] methods() {
return Binding.NO_METHODS;
}
public final ReferenceBinding outermostEnclosingType() {
ReferenceBinding current = this;
while (true) {
ReferenceBinding last = current;
if ((current = current.enclosingType()) == null)
return last;
}
}
//{ObjectTeams: the following output-oriented methods should
// never use field sourceName directly, but only sourceName()!
/**
* 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".
*/
// orig (if internal names are desired, add a method qualifiedInternalName(),
// here and in sub-classes.):
@Override
public char[] qualifiedSourceName() {
if (isMemberType())
return CharOperation.concat(enclosingType().qualifiedSourceName(), sourceName(), '.');
return sourceName();
}
/**
* Answer the receiver's signature.
*
* NOTE: This method should only be used during/after code gen.
*/
@Override
public char[] readableName() /*java.lang.Object, p.X<T> */ {
return readableName(true);
}
public char[] readableName(boolean showGenerics) /*java.lang.Object, p.X<T> */ {
char[] readableName;
if (isMemberType()) {
readableName = CharOperation.concat(enclosingType().readableName(showGenerics && hasEnclosingInstanceContext()), sourceName(), '.'); // OT: was this.sourceName
} else {
readableName = CharOperation.concatWith(this.compoundName, '.');
}
if (showGenerics) {
TypeVariableBinding[] typeVars;
//{ObjectTeams: include value parameters:
SyntheticArgumentBinding[] valueParams = valueParamSynthArgs();
/* orig:
if ((typeVars = typeVariables()) != Binding.NO_TYPE_VARIABLES) {
:giro */
if ((typeVars = typeVariables()) != Binding.NO_TYPE_VARIABLES || valueParams != Binding.NO_SYNTH_ARGUMENTS) {
// orig:
StringBuffer nameBuffer = new StringBuffer(10);
nameBuffer.append(readableName).append('<');
// :giro
for (int i = 0; i < valueParams.length; i++) {
nameBuffer.append('@');
nameBuffer.append(valueParams[i].readableName());
if (typeVars.length > 0)
nameBuffer.append(',');
}
// SH}
for (int i = 0, length = typeVars.length; i < length; i++) {
if (i > 0) nameBuffer.append(',');
nameBuffer.append(typeVars[i].readableName());
}
nameBuffer.append('>');
int nameLength = nameBuffer.length();
readableName = new char[nameLength];
nameBuffer.getChars(0, nameLength, readableName, 0);
}
}
return readableName;
}
protected void appendNullAnnotation(StringBuffer nameBuffer, CompilerOptions options) {
if (options.isAnnotationBasedNullAnalysisEnabled) {
if (options.usesNullTypeAnnotations()) {
for (AnnotationBinding annotation : this.typeAnnotations) {
ReferenceBinding annotationType = annotation.getAnnotationType();
if (annotationType.hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation)) {
nameBuffer.append('@').append(annotationType.shortReadableName()).append(' ');
}
}
} else {
// restore applied null annotation from tagBits:
if ((this.tagBits & TagBits.AnnotationNonNull) != 0) {
char[][] nonNullAnnotationName = options.nonNullAnnotationName;
nameBuffer.append('@').append(nonNullAnnotationName[nonNullAnnotationName.length-1]).append(' ');
}
if ((this.tagBits & TagBits.AnnotationNullable) != 0) {
char[][] nullableAnnotationName = options.nullableAnnotationName;
nameBuffer.append('@').append(nullableAnnotationName[nullableAnnotationName.length-1]).append(' ');
}
}
}
}
public AnnotationHolder retrieveAnnotationHolder(Binding binding, boolean forceInitialization) {
SimpleLookupTable store = storedAnnotations(forceInitialization, false);
return store == null ? null : (AnnotationHolder) store.get(binding);
}
//{ObjectTeams: accessible to classes in org.eclipse.objectteams...:
public
// SH}
AnnotationBinding[] retrieveAnnotations(Binding binding) {
AnnotationHolder holder = retrieveAnnotationHolder(binding, true);
return holder == null ? Binding.NO_ANNOTATIONS : holder.getAnnotations();
}
@Override
public void setAnnotations(AnnotationBinding[] annotations, boolean forceStore) {
storeAnnotations(this, annotations, forceStore);
}
public void setContainerAnnotationType(ReferenceBinding value) {
// Leave this to subclasses
}
public void tagAsHavingDefectiveContainerType() {
// Leave this to subclasses
}
/**
* @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#nullAnnotatedReadableName(CompilerOptions,boolean)
*/
@Override
public char[] nullAnnotatedReadableName(CompilerOptions options, boolean shortNames) {
if (shortNames)
return nullAnnotatedShortReadableName(options);
return nullAnnotatedReadableName(options);
}
char[] nullAnnotatedReadableName(CompilerOptions options) {
StringBuffer nameBuffer = new StringBuffer(10);
if (isMemberType()) {
nameBuffer.append(enclosingType().nullAnnotatedReadableName(options, false));
nameBuffer.append('.');
appendNullAnnotation(nameBuffer, options);
nameBuffer.append(this.sourceName);
} else if (this.compoundName != null) {
int i;
int l=this.compoundName.length;
for (i=0; i<l-1; i++) {
nameBuffer.append(this.compoundName[i]);
nameBuffer.append('.');
}
appendNullAnnotation(nameBuffer, options);
nameBuffer.append(this.compoundName[i]);
} else {
// case of TypeVariableBinding with nullAnnotationTagBits:
appendNullAnnotation(nameBuffer, options);
if (this.sourceName != null)
nameBuffer.append(this.sourceName);
else // WildcardBinding, CaptureBinding have no sourceName
nameBuffer.append(this.readableName());
}
TypeBinding [] arguments = typeArguments();
if (arguments != null && arguments.length > 0) { // empty arguments array happens when PTB has been created just to capture type annotations
nameBuffer.append('<');
for (int i = 0, length = arguments.length; i < length; i++) {
if (i > 0) nameBuffer.append(',');
nameBuffer.append(arguments[i].nullAnnotatedReadableName(options, false));
}
nameBuffer.append('>');
}
int nameLength = nameBuffer.length();
char[] readableName = new char[nameLength];
nameBuffer.getChars(0, nameLength, readableName, 0);
return readableName;
}
char[] nullAnnotatedShortReadableName(CompilerOptions options) {
StringBuffer nameBuffer = new StringBuffer(10);
if (isMemberType()) {
nameBuffer.append(enclosingType().nullAnnotatedReadableName(options, true));
nameBuffer.append('.');
appendNullAnnotation(nameBuffer, options);
nameBuffer.append(this.sourceName);
} else {
appendNullAnnotation(nameBuffer, options);
if (this.sourceName != null)
nameBuffer.append(this.sourceName);
else // WildcardBinding, CaptureBinding have no sourceName
nameBuffer.append(this.shortReadableName());
}
TypeBinding [] arguments = typeArguments();
if (arguments != null && arguments.length > 0) { // empty arguments array happens when PTB has been created just to capture type annotations
nameBuffer.append('<');
for (int i = 0, length = arguments.length; i < length; i++) {
if (i > 0) nameBuffer.append(',');
nameBuffer.append(arguments[i].nullAnnotatedReadableName(options, true));
}
nameBuffer.append('>');
}
int nameLength = nameBuffer.length();
char[] shortReadableName = new char[nameLength];
nameBuffer.getChars(0, nameLength, shortReadableName, 0);
return shortReadableName;
}
@Override
public char[] shortReadableName() /*Object*/ {
return shortReadableName(true);
}
public char[] shortReadableName(boolean showGenerics) /*Object*/ {
char[] shortReadableName;
if (isMemberType()) {
shortReadableName = CharOperation.concat(enclosingType().shortReadableName(showGenerics && hasEnclosingInstanceContext()), sourceName(), '.'); // OT: was this.sourceName
} else {
shortReadableName = sourceName(); // OT: was sourceName
}
if (showGenerics) {
TypeVariableBinding[] typeVars;
//{ObjectTeams: include value parameters:
SyntheticArgumentBinding[] valueParams = valueParamSynthArgs();
/* orig:
if ((typeVars = typeVariables()) != Binding.NO_TYPE_VARIABLES) {
:giro */
if ((typeVars = typeVariables()) != Binding.NO_TYPE_VARIABLES || valueParams != Binding.NO_SYNTH_ARGUMENTS) {
// orig:
StringBuffer nameBuffer = new StringBuffer(10);
nameBuffer.append(shortReadableName).append('<');
// :giro
for (int i = 0; i < valueParams.length; i++) {
nameBuffer.append('@');
nameBuffer.append(valueParams[i].shortReadableName());
if (typeVars.length > 0)
nameBuffer.append(',');
}
// SH}
for (int i = 0, length = typeVars.length; i < length; i++) {
if (i > 0) nameBuffer.append(',');
nameBuffer.append(typeVars[i].shortReadableName());
}
nameBuffer.append('>');
int nameLength = nameBuffer.length();
shortReadableName = new char[nameLength];
nameBuffer.getChars(0, nameLength, shortReadableName, 0);
}
}
return shortReadableName;
}
// SH} // end sourceName - edited section
//{ObjectTeams: to be overridden in RoleTypeBinding
public char[] optimalName() {
return readableName();
}
// SH}
//{ObjectTeams: beautify for completion:
@Override
public char[] genericTypeSignature(boolean retrenchCallin) {
char[] result = genericTypeSignature();
if (!retrenchCallin)
return result;
return CharOperation.replace(result, IOTConstants.OT_DELIM_NAME, new char[0]);
}
// SH}
@Override
public char[] signature() /* Ljava/lang/Object; */ {
if (this.signature != null)
return this.signature;
return this.signature = CharOperation.concat('L', constantPoolName(), ';');
}
@Override
public char[] sourceName() {
//{ObjectTeams: human readable source name, stripping __OT__ prefix if present
if (isSourceRole() && RoleSplitter.isClassPartName(this.sourceName))
return RoleSplitter.getInterfacePartName(this.sourceName);
return this.sourceName;
}
// original sourceName():
@Override
public char[] internalName() {
return this.sourceName;
}
// SH}
/**
* 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
*/
@Override
public ReferenceBinding 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
*/
@Override
public ReferenceBinding downwardsProjection(Scope scope, TypeBinding[] mentionedTypeVariables) {
return this;
}
void storeAnnotationHolder(Binding binding, AnnotationHolder holder) {
if (holder == null) {
SimpleLookupTable store = storedAnnotations(false, false);
if (store != null)
store.removeKey(binding);
} else {
SimpleLookupTable store = storedAnnotations(true, false);
if (store != null)
store.put(binding, holder);
}
}
//{ObjectTeams: accessible to classes in org.eclipse.objectteams...:
public
// SH}
void storeAnnotations(Binding binding, AnnotationBinding[] annotations, boolean forceStore) {
AnnotationHolder holder = null;
if (annotations == null || annotations.length == 0) {
SimpleLookupTable store = storedAnnotations(false, forceStore);
if (store != null)
holder = (AnnotationHolder) store.get(binding);
if (holder == null) return; // nothing to delete
} else {
SimpleLookupTable store = storedAnnotations(true, forceStore);
if (store == null) return; // not supported
holder = (AnnotationHolder) store.get(binding);
if (holder == null)
holder = new AnnotationHolder();
}
storeAnnotationHolder(binding, holder.setAnnotations(annotations));
}
SimpleLookupTable storedAnnotations(boolean forceInitialize, boolean forceStore) {
return null; // overrride if interested in storing annotations for the receiver, its fields and methods
}
@Override
public ReferenceBinding superclass() {
return null;
}
@Override
public ReferenceBinding[] superInterfaces() {
return Binding.NO_SUPERINTERFACES;
}
public ReferenceBinding[] syntheticEnclosingInstanceTypes() {
if (isStatic()) return null;
ReferenceBinding enclosingType = enclosingType();
if (enclosingType == null)
return null;
return new ReferenceBinding[] {enclosingType};
}
MethodBinding[] unResolvedMethods() { // for the MethodVerifier so it doesn't resolve types
return methods();
}
public FieldBinding[] unResolvedFields() {
return Binding.NO_FIELDS;
}
/*
* If a type - known to be a Closeable - is mentioned in one of our white lists
* answer the typeBit for the white list (BitWrapperCloseable or BitResourceFreeCloseable).
*/
protected int applyCloseableClassWhitelists(CompilerOptions options) {
switch (this.compoundName.length) {
case 3:
if (CharOperation.equals(TypeConstants.JAVA, this.compoundName[0])) {
if (CharOperation.equals(TypeConstants.IO, this.compoundName[1])) {
char[] simpleName = this.compoundName[2];
int l = TypeConstants.JAVA_IO_WRAPPER_CLOSEABLES.length;
for (int i = 0; i < l; i++) {
if (CharOperation.equals(simpleName, TypeConstants.JAVA_IO_WRAPPER_CLOSEABLES[i]))
return TypeIds.BitWrapperCloseable;
}
l = TypeConstants.JAVA_IO_RESOURCE_FREE_CLOSEABLES.length;
for (int i = 0; i < l; i++) {
if (CharOperation.equals(simpleName, TypeConstants.JAVA_IO_RESOURCE_FREE_CLOSEABLES[i]))
return TypeIds.BitResourceFreeCloseable;
}
}
}
break;
case 4:
if (CharOperation.equals(TypeConstants.JAVA, this.compoundName[0])) {
if (CharOperation.equals(TypeConstants.UTIL, this.compoundName[1])) {
if (CharOperation.equals(TypeConstants.ZIP, this.compoundName[2])) {
char[] simpleName = this.compoundName[3];
int l = TypeConstants.JAVA_UTIL_ZIP_WRAPPER_CLOSEABLES.length;
for (int i = 0; i < l; i++) {
if (CharOperation.equals(simpleName, TypeConstants.JAVA_UTIL_ZIP_WRAPPER_CLOSEABLES[i]))
return TypeIds.BitWrapperCloseable;
}
}
}
}
break;
}
int l = TypeConstants.OTHER_WRAPPER_CLOSEABLES.length;
for (int i = 0; i < l; i++) {
if (CharOperation.equals(this.compoundName, TypeConstants.OTHER_WRAPPER_CLOSEABLES[i]))
return TypeIds.BitWrapperCloseable;
}
if (options.analyseResourceLeaks) {
ReferenceBinding mySuper = this.superclass();
if (mySuper != null && mySuper.id != TypeIds.T_JavaLangObject) {
if (hasMethodWithNumArgs(TypeConstants.CLOSE, 0))
return 0; // close methods indicates: class may need more closing than super
return mySuper.applyCloseableClassWhitelists(options);
}
}
return 0;
}
protected boolean hasMethodWithNumArgs(char[] selector, int numArgs) {
for (MethodBinding methodBinding : unResolvedMethods()) {
if (CharOperation.equals(methodBinding.selector, selector)
&& methodBinding.parameters.length == numArgs) {
return true;
}
}
return false;
}
/*
* If a type - known to be a Closeable - is mentioned in one of our white lists
* answer the typeBit for the white list (BitWrapperCloseable or BitResourceFreeCloseable).
*/
protected int applyCloseableInterfaceWhitelists() {
switch (this.compoundName.length) {
case 4:
for (int i=0; i<2; i++)
if (!CharOperation.equals(this.compoundName[i], TypeConstants.JAVA_UTIL_STREAM[i]))
return 0;
for (char[] streamName : TypeConstants.RESOURCE_FREE_CLOSEABLE_J_U_STREAMS)
if (CharOperation.equals(this.compoundName[3], streamName))
return TypeIds.BitResourceFreeCloseable;
break;
}
return 0;
}
//{ObjectTeams: support for checking substitution of a value parameter
public VariableBinding valueParamSynthArgAt(int typeParamPosition) {
SyntheticArgumentBinding[] args = valueParamSynthArgs();
if (args.length > typeParamPosition)
return args[typeParamPosition];
return null;
}
// SH}
protected MethodBinding [] getInterfaceAbstractContracts(Scope scope, boolean replaceWildcards, boolean filterDefaultMethods) throws InvalidInputException {
if (!isInterface() || !isValidBinding()) {
throw new InvalidInputException("Not a functional interface"); //$NON-NLS-1$
}
MethodBinding [] methods = methods();
MethodBinding [] contracts = new MethodBinding[0];
int contractsCount = 0;
int contractsLength = 0;
ReferenceBinding [] superInterfaces = superInterfaces();
for (int i = 0, length = superInterfaces.length; i < length; i++) {
// filterDefaultMethods=false => keep default methods needed to filter out any abstract methods they may override:
MethodBinding [] superInterfaceContracts = superInterfaces[i].getInterfaceAbstractContracts(scope, replaceWildcards, false);
final int superInterfaceContractsLength = superInterfaceContracts == null ? 0 : superInterfaceContracts.length;
if (superInterfaceContractsLength == 0) continue;
if (contractsLength < contractsCount + superInterfaceContractsLength) {
System.arraycopy(contracts, 0, contracts = new MethodBinding[contractsLength = contractsCount + superInterfaceContractsLength], 0, contractsCount);
}
System.arraycopy(superInterfaceContracts, 0, contracts, contractsCount, superInterfaceContractsLength);
contractsCount += superInterfaceContractsLength;
}
LookupEnvironment environment = scope.environment();
for (int i = 0, length = methods == null ? 0 : methods.length; i < length; i++) {
final MethodBinding method = methods[i];
if (method == null || method.isStatic() || method.redeclaresPublicObjectMethod(scope) || method.isPrivate())
continue;
if (!method.isValidBinding())
throw new InvalidInputException("Not a functional interface"); //$NON-NLS-1$
for (int j = 0; j < contractsCount;) {
if ( contracts[j] != null && MethodVerifier.doesMethodOverride(method, contracts[j], environment)) {
contractsCount--;
// abstract method from super type overridden by present interface ==> contracts[j] = null;
if (j < contractsCount) {
System.arraycopy(contracts, j+1, contracts, j, contractsCount - j);
continue;
}
}
j++;
}
if (filterDefaultMethods && method.isDefaultMethod())
continue; // skip default method itself
if (contractsCount == contractsLength) {
System.arraycopy(contracts, 0, contracts = new MethodBinding[contractsLength += 16], 0, contractsCount);
}
if(environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) {
ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(method, scope);
}
contracts[contractsCount++] = method;
}
// check mutual overriding of inherited methods (i.e., not from current type):
for (int i = 0; i < contractsCount; i++) {
MethodBinding contractI = contracts[i];
if (TypeBinding.equalsEquals(contractI.declaringClass, this))
continue;
for (int j = 0; j < contractsCount; j++) {
MethodBinding contractJ = contracts[j];
if (i == j || TypeBinding.equalsEquals(contractJ.declaringClass, this))
continue;
if (contractI == contractJ || MethodVerifier.doesMethodOverride(contractI, contractJ, environment)) {
contractsCount--;
// abstract method from one super type overridden by other super interface ==> contracts[j] = null;
if (j < contractsCount) {
System.arraycopy(contracts, j+1, contracts, j, contractsCount - j);
}
j--;
if (j < i)
i--;
continue;
}
}
if (filterDefaultMethods && contractI.isDefaultMethod()) {
contractsCount--;
// remove default method after it has eliminated any matching abstract methods from contracts
if (i < contractsCount) {
System.arraycopy(contracts, i+1, contracts, i, contractsCount - i);
}
i--;
}
}
if (contractsCount < contractsLength) {
System.arraycopy(contracts, 0, contracts = new MethodBinding[contractsCount], 0, contractsCount);
}
return contracts;
}
@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];
}
if (this.compoundName != null)
scope.compilationUnitScope().recordQualifiedReference(this.compoundName);
MethodBinding[] methods = null;
try {
methods = getInterfaceAbstractContracts(scope, replaceWildcards, true);
if (methods == null || methods.length == 0)
return this.singleAbstractMethod[index] = samProblemBinding;
int contractParameterLength = 0;
char [] contractSelector = null;
for (int i = 0, length = methods.length; i < length; i++) {
MethodBinding method = methods[i];
if (method == null) continue;
if (contractSelector == null) {
contractSelector = method.selector;
contractParameterLength = method.parameters == null ? 0 : method.parameters.length;
} else {
int methodParameterLength = method.parameters == null ? 0 : method.parameters.length;
if (methodParameterLength != contractParameterLength || !CharOperation.equals(method.selector, contractSelector))
return this.singleAbstractMethod[index] = samProblemBinding;
}
}
} catch (InvalidInputException e) {
return this.singleAbstractMethod[index] = samProblemBinding;
}
if (methods.length == 1)
return this.singleAbstractMethod[index] = methods[0];
final LookupEnvironment environment = scope.environment();
boolean genericMethodSeen = false;
int length = methods.length;
boolean analyseNullAnnotations = environment.globalOptions.isAnnotationBasedNullAnalysisEnabled;
next:for (int i = length - 1; i >= 0; --i) {
MethodBinding method = methods[i], otherMethod = null;
if (method.typeVariables != Binding.NO_TYPE_VARIABLES)
genericMethodSeen = true;
TypeBinding returnType = method.returnType;
TypeBinding[] parameters = method.parameters;
for (int j = 0; j < length; j++) {
if (i == j) continue;
otherMethod = methods[j];
if (otherMethod.typeVariables != Binding.NO_TYPE_VARIABLES)
genericMethodSeen = true;
if (genericMethodSeen) { // adapt type parameters.
otherMethod = MethodVerifier.computeSubstituteMethod(otherMethod, method, environment);
if (otherMethod == null)
continue next;
}
if (!MethodVerifier.isSubstituteParameterSubsignature(method, otherMethod, environment) || !MethodVerifier.areReturnTypesCompatible(method, otherMethod, environment))
continue next;
if (analyseNullAnnotations) {
returnType = NullAnnotationMatching.strongerType(returnType, otherMethod.returnType, environment);
parameters = NullAnnotationMatching.weakerTypes(parameters, otherMethod.parameters, environment);
}
}
// If we reach here, we found a method that is override equivalent with every other method and is also return type substitutable. Compute kosher exceptions now ...
ReferenceBinding [] exceptions = new ReferenceBinding[0];
int exceptionsCount = 0, exceptionsLength = 0;
final MethodBinding theAbstractMethod = method;
boolean shouldEraseThrows = theAbstractMethod.typeVariables == Binding.NO_TYPE_VARIABLES && genericMethodSeen;
boolean shouldAdaptThrows = theAbstractMethod.typeVariables != Binding.NO_TYPE_VARIABLES;
final int typeVariableLength = theAbstractMethod.typeVariables.length;
none:for (i = 0; i < length; i++) {
method = methods[i];
ReferenceBinding[] methodThrownExceptions = method.thrownExceptions;
int methodExceptionsLength = methodThrownExceptions == null ? 0: methodThrownExceptions.length;
if (methodExceptionsLength == 0) break none;
if (shouldAdaptThrows && method != theAbstractMethod) {
System.arraycopy(methodThrownExceptions, 0, methodThrownExceptions = new ReferenceBinding[methodExceptionsLength], 0, methodExceptionsLength);
for (int tv = 0; tv < typeVariableLength; tv++) {
if (methodThrownExceptions[tv] instanceof TypeVariableBinding) {
methodThrownExceptions[tv] = theAbstractMethod.typeVariables[tv];
}
}
}
nextException: for (int j = 0; j < methodExceptionsLength; j++) {
ReferenceBinding methodException = methodThrownExceptions[j];
if (shouldEraseThrows)
methodException = (ReferenceBinding) methodException.erasure();
nextMethod: for (int k = 0; k < length; k++) {
if (i == k) continue;
otherMethod = methods[k];
ReferenceBinding[] otherMethodThrownExceptions = otherMethod.thrownExceptions;
int otherMethodExceptionsLength = otherMethodThrownExceptions == null ? 0 : otherMethodThrownExceptions.length;
if (otherMethodExceptionsLength == 0) break none;
if (shouldAdaptThrows && otherMethod != theAbstractMethod) {
System.arraycopy(otherMethodThrownExceptions,
0,
otherMethodThrownExceptions = new ReferenceBinding[otherMethodExceptionsLength],
0,
otherMethodExceptionsLength);
for (int tv = 0; tv < typeVariableLength; tv++) {
if (otherMethodThrownExceptions[tv] instanceof TypeVariableBinding) {
otherMethodThrownExceptions[tv] = theAbstractMethod.typeVariables[tv];
}
}
}
for (int l = 0; l < otherMethodExceptionsLength; l++) {
ReferenceBinding otherException = otherMethodThrownExceptions[l];
if (shouldEraseThrows)
otherException = (ReferenceBinding) otherException.erasure();
if (methodException.isCompatibleWith(otherException))
continue nextMethod;
}
continue nextException;
}
// If we reach here, method exception or its super type is covered by every throws clause.
if (exceptionsCount == exceptionsLength) {
System.arraycopy(exceptions, 0, exceptions = new ReferenceBinding[exceptionsLength += 16], 0, exceptionsCount);
}
exceptions[exceptionsCount++] = methodException;
}
}
if (exceptionsCount != exceptionsLength) {
System.arraycopy(exceptions, 0, exceptions = new ReferenceBinding[exceptionsCount], 0, exceptionsCount);
}
this.singleAbstractMethod[index] = new MethodBinding(theAbstractMethod.modifiers | ClassFileConstants.AccSynthetic,
theAbstractMethod.selector,
returnType,
parameters,
exceptions,
theAbstractMethod.declaringClass);
this.singleAbstractMethod[index].typeVariables = theAbstractMethod.typeVariables;
return this.singleAbstractMethod[index];
}
return this.singleAbstractMethod[index] = samProblemBinding;
}
// See JLS 4.9 bullet 1
public static boolean isConsistentIntersection(TypeBinding[] intersectingTypes) {
TypeBinding[] ci = new TypeBinding[intersectingTypes.length];
for (int i = 0; i < ci.length; i++) {
TypeBinding current = intersectingTypes[i];
ci[i] = (current.isClass() || current.isArrayType())
? current : current.superclass();
}
TypeBinding mostSpecific = ci[0];
for (int i = 1; i < ci.length; i++) {
TypeBinding current = ci[i];
// when invoked during type inference we only want to check inconsistency among real types:
if (current.isTypeVariable() || current.isWildcard() || !current.isProperType(true))
continue;
if (mostSpecific.isSubtypeOf(current, false))
continue;
else if (current.isSubtypeOf(mostSpecific, false))
mostSpecific = current;
else
return false;
}
return true;
}
public ModuleBinding module() {
if (this.fPackage != null)
return this.fPackage.enclosingModule;
return null;
}
public boolean hasEnclosingInstanceContext() {
if (isMemberType() && !isStatic())
return true;
MethodBinding enclosingMethod = enclosingMethod();
if (enclosingMethod != null)
return !enclosingMethod.isStatic();
return false;
}
}