package org.eclipse.jdt.internal.compiler.ast;
import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.INVOCATION_CONTEXT;
import java.util.HashMap;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationPosition;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
import org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
import org.eclipse.jdt.internal.compiler.codegen.Opcodes;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.flow.FieldInitsFakingFlowContext;
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.impl.IrritantSet;
import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
import org.eclipse.jdt.internal.compiler.lookup.ImplicitNullAnnotationVerifier;
import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18;
import org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.PolyTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding;
import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.jdt.internal.compiler.parser.Parser;
import org.eclipse.jdt.internal.compiler.parser.Scanner;
public class ReferenceExpression extends FunctionalExpression implements IPolyExpression, InvocationSite {
private static final String SecretReceiverVariableName = " rec_";
private static final char[] ImplicitArgName = " arg".toCharArray();
public LocalVariableBinding receiverVariable;
public Expression lhs;
public TypeReference [] typeArguments;
public char [] selector;
public int nameSourceStart;
public TypeBinding receiverType;
public boolean haveReceiver;
public TypeBinding[] resolvedTypeArguments;
private boolean typeArgumentsHaveErrors;
MethodBinding syntheticAccessor;
private int depth;
private MethodBinding exactMethodBinding;
private boolean receiverPrecedesParameters = false;
private TypeBinding[] freeParameters;
private boolean checkingPotentialCompatibility;
private MethodBinding[] potentialMethods = Binding.NO_METHODS;
protected ReferenceExpression original;
private HashMap<TypeBinding, ReferenceExpression> copiesPerTargetType;
public char[] text;
private HashMap<ParameterizedGenericMethodBinding, InferenceContext18> inferenceContexts;
private Scanner scanner;
public ReferenceExpression(Scanner scanner) {
super();
this.original = this;
this.scanner = scanner;
}
public void initialize(CompilationResult result, Expression expression, TypeReference [] optionalTypeArguments, char [] identifierOrNew, int sourceEndPosition) {
super.setCompilationResult(result);
this.lhs = expression;
this.typeArguments = optionalTypeArguments;
this.selector = identifierOrNew;
this.sourceStart = expression.sourceStart;
this.sourceEnd = sourceEndPosition;
}
private ReferenceExpression copy() {
final Parser parser = new Parser(this.enclosingScope.problemReporter(), false);
final ICompilationUnit compilationUnit = this.compilationResult.getCompilationUnit();
final char[] source = compilationUnit != null ? compilationUnit.getContents() : this.text;
parser.scanner = this.scanner;
ReferenceExpression copy = (ReferenceExpression) parser.parseExpression(source, compilationUnit != null ? this.sourceStart : 0, this.sourceEnd - this.sourceStart + 1,
this.enclosingScope.referenceCompilationUnit(), false );
copy.original = this;
copy.sourceStart = this.sourceStart;
copy.sourceEnd = this.sourceEnd;
return copy;
}
private boolean shouldGenerateSecretReceiverVariable() {
if (isMethodReference() && this.haveReceiver) {
if (this.lhs instanceof Invocation)
return true;
else {
return new ASTVisitor() {
boolean accessesnonFinalOuterLocals;
@Override
public boolean visit(SingleNameReference name, BlockScope skope) {
Binding local = skope.getBinding(name.getName(), ReferenceExpression.this);
if (local instanceof LocalVariableBinding) {
LocalVariableBinding localBinding = (LocalVariableBinding) local;
if (!localBinding.isFinal() && !localBinding.isEffectivelyFinal()) {
this.accessesnonFinalOuterLocals = true;
}
}
return false;
}
public boolean accessesnonFinalOuterLocals() {
ReferenceExpression.this.lhs.traverse(this, ReferenceExpression.this.enclosingScope);
return this.accessesnonFinalOuterLocals;
}
}.accessesnonFinalOuterLocals();
}
}
return false;
}
public void generateImplicitLambda(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
ReferenceExpression copy = copy();
int argc = this.descriptor.parameters.length;
LambdaExpression implicitLambda = new LambdaExpression(this.compilationResult, false, (this.binding.modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0);
Argument [] arguments = new Argument[argc];
for (int i = 0; i < argc; i++)
arguments[i] = new Argument(CharOperation.append(ImplicitArgName, Integer.toString(i).toCharArray()), 0, null, 0, true);
implicitLambda.setArguments(arguments);
implicitLambda.setExpressionContext(this.expressionContext);
implicitLambda.setExpectedType(this.expectedType);
int parameterShift = this.receiverPrecedesParameters ? 1 : 0;
Expression [] argv = new SingleNameReference[argc - parameterShift];
for (int i = 0, length = argv.length; i < length; i++) {
char[] name = CharOperation.append(ImplicitArgName, Integer.toString((i + parameterShift)).toCharArray());
argv[i] = new SingleNameReference(name, 0);
}
boolean generateSecretReceiverVariable = shouldGenerateSecretReceiverVariable();
if (isMethodReference()) {
if (generateSecretReceiverVariable) {
this.lhs.generateCode(currentScope, codeStream, true);
codeStream.store(this.receiverVariable, false);
codeStream.addVariable(this.receiverVariable);
}
MessageSend message = new MessageSend();
message.selector = this.selector;
Expression receiver = generateSecretReceiverVariable ? new SingleNameReference(this.receiverVariable.name, 0) : copy.lhs;
message.receiver = this.receiverPrecedesParameters ?
new SingleNameReference(CharOperation.append(ImplicitArgName, Integer.toString(0).toCharArray()), 0) : receiver;
message.typeArguments = copy.typeArguments;
message.arguments = argv;
implicitLambda.setBody(message);
} else if (isArrayConstructorReference()) {
ArrayAllocationExpression arrayAllocationExpression = new ArrayAllocationExpression();
arrayAllocationExpression.dimensions = new Expression[] { argv[0] };
if (this.lhs instanceof ArrayTypeReference) {
ArrayTypeReference arrayTypeReference = (ArrayTypeReference) this.lhs;
arrayAllocationExpression.type = arrayTypeReference.dimensions == 1 ? new SingleTypeReference(arrayTypeReference.token, 0L) :
new ArrayTypeReference(arrayTypeReference.token, arrayTypeReference.dimensions - 1, 0L);
} else {
ArrayQualifiedTypeReference arrayQualifiedTypeReference = (ArrayQualifiedTypeReference) this.lhs;
arrayAllocationExpression.type = arrayQualifiedTypeReference.dimensions == 1 ? new QualifiedTypeReference(arrayQualifiedTypeReference.tokens, arrayQualifiedTypeReference.sourcePositions)
: new ArrayQualifiedTypeReference(arrayQualifiedTypeReference.tokens, arrayQualifiedTypeReference.dimensions - 1,
arrayQualifiedTypeReference.sourcePositions);
}
implicitLambda.setBody(arrayAllocationExpression);
} else {
AllocationExpression allocation = new AllocationExpression();
if (this.lhs instanceof TypeReference) {
allocation.type = (TypeReference) this.lhs;
} else if (this.lhs instanceof SingleNameReference) {
allocation.type = new SingleTypeReference(((SingleNameReference) this.lhs).token, 0);
} else if (this.lhs instanceof QualifiedNameReference) {
allocation.type = new QualifiedTypeReference(((QualifiedNameReference) this.lhs).tokens, new long [((QualifiedNameReference) this.lhs).tokens.length]);
} else {
throw new IllegalStateException("Unexpected node type");
}
allocation.typeArguments = copy.typeArguments;
allocation.arguments = argv;
implicitLambda.setBody(allocation);
}
BlockScope lambdaScope = this.receiverVariable != null ? this.receiverVariable.declaringScope : currentScope;
IErrorHandlingPolicy oldPolicy = lambdaScope.problemReporter().switchErrorHandlingPolicy(silentErrorHandlingPolicy);
try {
implicitLambda.resolveType(lambdaScope, true);
implicitLambda.analyseCode(lambdaScope,
new FieldInitsFakingFlowContext(null, this, Binding.NO_EXCEPTIONS, null, lambdaScope, FlowInfo.DEAD_END),
UnconditionalFlowInfo.fakeInitializedFlowInfo(lambdaScope.outerMostMethodScope().analysisIndex, lambdaScope.referenceType().maxFieldCount));
} finally {
lambdaScope.problemReporter().switchErrorHandlingPolicy(oldPolicy);
}
SyntheticArgumentBinding[] outerLocals = this.receiverType.syntheticOuterLocalVariables();
for (int i = 0, length = outerLocals == null ? 0 : outerLocals.length; i < length; i++)
implicitLambda.addSyntheticArgument(outerLocals[i].actualOuterLocalVariable);
implicitLambda.generateCode(lambdaScope, codeStream, valueRequired);
if (generateSecretReceiverVariable) {
codeStream.removeVariable(this.receiverVariable);
}
}
private boolean shouldGenerateImplicitLambda(BlockScope currentScope) {
return (this.binding.isVarargs() ||
(isConstructorReference() && this.receiverType.syntheticOuterLocalVariables() != null && this.shouldCaptureInstance) ||
this.requiresBridges() ||
!isDirectCodeGenPossible());
}
private boolean isDirectCodeGenPossible() {
if (this.binding != null) {
if (isMethodReference() && this.syntheticAccessor == null) {
if (TypeBinding.notEquals(this.binding.declaringClass, this.lhs.resolvedType.erasure())) {
if (!this.binding.declaringClass.canBeSeenBy(this.enclosingScope)) {
return !(this.binding.isFinal() || this.binding.isStatic());
}
}
}
TypeBinding[] descriptorParams = this.descriptor.parameters;
TypeBinding[] origParams = this.binding.original().parameters;
TypeBinding[] origDescParams = this.descriptor.original().parameters;
int offset = this.receiverPrecedesParameters ? 1 : 0;
for (int i = 0; i < descriptorParams.length - offset; i++) {
TypeBinding descType = descriptorParams[i + offset];
TypeBinding origDescType = origDescParams[i + offset];
if (descType.isIntersectionType18() ||
(descType.isTypeVariable() && ((TypeVariableBinding) descType).boundsCount() > 1)) {
return CharOperation.equals(origDescType.signature(), origParams[i].signature());
}
}
}
return true;
}
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
this.actualMethodBinding = this.binding;
if (shouldGenerateImplicitLambda(currentScope)) {
generateImplicitLambda(currentScope, codeStream, valueRequired);
return;
}
SourceTypeBinding sourceType = currentScope.enclosingSourceType();
if (this.receiverType.isArrayType()) {
char [] lambdaName = CharOperation.concat(TypeConstants.ANONYMOUS_METHOD, Integer.toString(this.ordinal).toCharArray());
if (isConstructorReference()) {
this.actualMethodBinding = this.binding = sourceType.addSyntheticArrayMethod((ArrayBinding) this.receiverType, SyntheticMethodBinding.ArrayConstructor, lambdaName);
} else if (CharOperation.equals(this.selector, TypeConstants.CLONE)) {
this.actualMethodBinding = this.binding = sourceType.addSyntheticArrayMethod((ArrayBinding) this.receiverType, SyntheticMethodBinding.ArrayClone, lambdaName);
}
} else if (this.syntheticAccessor != null) {
if (this.lhs.isSuper() || isMethodReference())
this.binding = this.syntheticAccessor;
} else {
if (this.binding != null && isMethodReference()) {
if (TypeBinding.notEquals(this.binding.declaringClass, this.lhs.resolvedType.erasure())) {
if (!this.binding.declaringClass.canBeSeenBy(currentScope)) {
this.binding = new MethodBinding(this.binding.original(), (ReferenceBinding) this.lhs.resolvedType.erasure());
}
}
}
}
int pc = codeStream.position;
StringBuffer buffer = new StringBuffer();
int argumentsSize = 0;
buffer.append('(');
if (this.haveReceiver) {
this.lhs.generateCode(currentScope, codeStream, true);
if (isMethodReference() && !this.lhs.isThis() && !this.lhs.isSuper()) {
MethodBinding mb = currentScope.getJavaLangObject().getExactMethod(TypeConstants.GETCLASS,
Binding.NO_PARAMETERS, currentScope.compilationUnitScope());
codeStream.dup();
codeStream.invoke(Opcodes.OPC_invokevirtual, mb, mb.declaringClass);
codeStream.pop();
}
if (this.lhs.isSuper() && !this.actualMethodBinding.isPrivate()) {
if (this.lhs instanceof QualifiedSuperReference) {
QualifiedSuperReference qualifiedSuperReference = (QualifiedSuperReference) this.lhs;
TypeReference qualification = qualifiedSuperReference.qualification;
if (qualification.resolvedType.isInterface()) {
buffer.append(sourceType.signature());
} else {
buffer.append(((QualifiedSuperReference) this.lhs).currentCompatibleType.signature());
}
} else {
buffer.append(sourceType.signature());
}
} else {
buffer.append(this.receiverType.signature());
}
argumentsSize = 1;
} else {
if (this.isConstructorReference()) {
ReferenceBinding[] enclosingInstances = Binding.UNINITIALIZED_REFERENCE_TYPES;
if (this.receiverType.isNestedType()) {
ReferenceBinding nestedType = (ReferenceBinding) this.receiverType;
if ((enclosingInstances = nestedType.syntheticEnclosingInstanceTypes()) != null) {
int length = enclosingInstances.length;
argumentsSize = length;
for (int i = 0 ; i < length; i++) {
ReferenceBinding syntheticArgumentType = enclosingInstances[i];
buffer.append(syntheticArgumentType.signature());
Object[] emulationPath = currentScope.getEmulationPath(
syntheticArgumentType,
false ,
true );
codeStream.generateOuterAccess(emulationPath, this, syntheticArgumentType, currentScope);
}
} else {
enclosingInstances = Binding.NO_REFERENCE_TYPES;
}
}
if (this.syntheticAccessor != null) {
char [] lambdaName = CharOperation.concat(TypeConstants.ANONYMOUS_METHOD, Integer.toString(this.ordinal).toCharArray());
this.binding = sourceType.addSyntheticFactoryMethod(this.binding, this.syntheticAccessor, enclosingInstances, lambdaName);
this.syntheticAccessor = null;
}
}
}
buffer.append(')');
buffer.append('L');
if (this.resolvedType.isIntersectionType18()) {
buffer.append(this.descriptor.declaringClass.constantPoolName());
} else {
buffer.append(this.resolvedType.constantPoolName());
}
buffer.append(';');
if (this.isSerializable) {
sourceType.addSyntheticMethod(this);
}
int invokeDynamicNumber = codeStream.classFile.recordBootstrapMethod(this);
codeStream.invokeDynamic(invokeDynamicNumber, argumentsSize, 1, this.descriptor.selector, buffer.toString().toCharArray(),
this.isConstructorReference(), (this.lhs instanceof TypeReference? (TypeReference) this.lhs : null), this.typeArguments);
if (!valueRequired)
codeStream.pop();
codeStream.recordPositionsFrom(pc, this.sourceStart);
}
@Override
public void cleanUp() {
if (this.copiesPerTargetType != null) {
for (ReferenceExpression copy : this.copiesPerTargetType.values())
copy.scanner = null;
}
if (this.original != null && this.original != this) {
this.original.cleanUp();
}
this.scanner = null;
this.receiverVariable = null;
}
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0 || this.binding == null || !this.binding.isValidBinding())
return;
MethodBinding codegenBinding = this.binding.original();
if (codegenBinding.isVarargs())
return;
SourceTypeBinding enclosingSourceType = currentScope.enclosingSourceType();
if (this.isConstructorReference()) {
ReferenceBinding allocatedType = codegenBinding.declaringClass;
if (codegenBinding.isPrivate() &&
TypeBinding.notEquals(enclosingSourceType, (allocatedType = codegenBinding.declaringClass))) {
if ((allocatedType.tagBits & TagBits.IsLocalType) != 0) {
codegenBinding.tagBits |= TagBits.ClearPrivateModifier;
} else {
if (currentScope.enclosingSourceType().isNestmateOf(this.binding.declaringClass)) {
this.syntheticAccessor = codegenBinding;
return;
}
this.syntheticAccessor = ((SourceTypeBinding) allocatedType).addSyntheticMethod(codegenBinding, false);
currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this);
}
}
return;
}
if (this.binding.isPrivate()) {
if (TypeBinding.notEquals(enclosingSourceType, codegenBinding.declaringClass)){
this.syntheticAccessor = ((SourceTypeBinding)codegenBinding.declaringClass).addSyntheticMethod(codegenBinding, false );
currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this);
}
return;
}
if (this.lhs.isSuper()) {
SourceTypeBinding destinationType = enclosingSourceType;
if (this.lhs instanceof QualifiedSuperReference) {
QualifiedSuperReference qualifiedSuperReference = (QualifiedSuperReference) this.lhs;
TypeReference qualification = qualifiedSuperReference.qualification;
if (!qualification.resolvedType.isInterface())
destinationType = (SourceTypeBinding) (qualifiedSuperReference.currentCompatibleType);
}
this.syntheticAccessor = destinationType.addSyntheticMethod(codegenBinding, true);
currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this);
return;
}
if (this.binding.isProtected() && (this.bits & ASTNode.DepthMASK) != 0 && codegenBinding.declaringClass.getPackage() != enclosingSourceType.getPackage()) {
SourceTypeBinding currentCompatibleType = (SourceTypeBinding) enclosingSourceType.enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT);
this.syntheticAccessor = currentCompatibleType.addSyntheticMethod(codegenBinding, isSuperAccess());
currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this);
return;
}
}
@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
if (this.haveReceiver) {
this.lhs.analyseCode(currentScope, flowContext, flowInfo, true);
this.lhs.checkNPE(currentScope, flowContext, flowInfo);
} else if (isConstructorReference()) {
TypeBinding type = this.receiverType.leafComponentType();
if (type.isNestedType() &&
type instanceof ReferenceBinding && !((ReferenceBinding)type).isStatic()) {
currentScope.tagAsAccessingEnclosingInstanceStateOf((ReferenceBinding)type, false);
this.shouldCaptureInstance = true;
ReferenceBinding allocatedTypeErasure = (ReferenceBinding) type.erasure();
if (allocatedTypeErasure.isLocalType()) {
((LocalTypeBinding) allocatedTypeErasure).addInnerEmulationDependent(currentScope, false);
}
}
}
if (currentScope.compilerOptions().isAnyEnabled(IrritantSet.UNLIKELY_ARGUMENT_TYPE) && this.binding.isValidBinding()
&& this.binding != null && this.binding.parameters != null) {
if (this.binding.parameters.length == 1
&& this.descriptor.parameters.length == (this.receiverPrecedesParameters ? 2 : 1)
&& !this.binding.isStatic()) {
final TypeBinding argumentType = this.descriptor.parameters[this.receiverPrecedesParameters ? 1 : 0];
final TypeBinding actualReceiverType = this.receiverPrecedesParameters ? this.descriptor.parameters[0] : this.binding.declaringClass;
UnlikelyArgumentCheck argumentCheck = UnlikelyArgumentCheck
.determineCheckForNonStaticSingleArgumentMethod(argumentType, currentScope, this.selector,
actualReceiverType, this.binding.parameters);
if (argumentCheck != null && argumentCheck.isDangerous(currentScope)) {
currentScope.problemReporter().unlikelyArgumentType(this, this.binding, argumentType,
argumentCheck.typeToReport, argumentCheck.dangerousMethod);
}
} else if (this.binding.parameters.length == 2 && this.descriptor.parameters.length == 2 && this.binding.isStatic()) {
final TypeBinding argumentType1 = this.descriptor.parameters[0];
final TypeBinding argumentType2 = this.descriptor.parameters[1];
UnlikelyArgumentCheck argumentCheck = UnlikelyArgumentCheck
.determineCheckForStaticTwoArgumentMethod(argumentType2, currentScope, this.selector,
argumentType1, this.binding.parameters, this.receiverType);
if (argumentCheck != null && argumentCheck.isDangerous(currentScope)) {
currentScope.problemReporter().unlikelyArgumentType(this, this.binding, argumentType2,
argumentCheck.typeToReport, argumentCheck.dangerousMethod);
}
}
}
if (currentScope.compilerOptions().analyseResourceLeaks) {
if (this.haveReceiver && CharOperation.equals(this.selector, TypeConstants.CLOSE)) {
FakedTrackingVariable trackingVariable = FakedTrackingVariable.getCloseTrackingVariable(this.lhs, flowInfo, flowContext);
if (trackingVariable != null) {
trackingVariable.markClosedInNestedMethod();
}
}
}
manageSyntheticAccessIfNecessary(currentScope, flowInfo);
return flowInfo;
}
@Override
public boolean checkingPotentialCompatibility() {
return this.checkingPotentialCompatibility;
}
@Override
public void acceptPotentiallyCompatibleMethods(MethodBinding[] methods) {
if (this.checkingPotentialCompatibility)
this.potentialMethods = methods;
}
@Override
public TypeBinding resolveType(BlockScope scope) {
final CompilerOptions compilerOptions = scope.compilerOptions();
TypeBinding lhsType;
if (this.constant != Constant.NotAConstant) {
this.constant = Constant.NotAConstant;
this.enclosingScope = scope;
if (this.original == this)
this.ordinal = recordFunctionalType(scope);
this.lhs.bits |= ASTNode.IgnoreRawTypeCheck;
lhsType = this.lhs.resolveType(scope);
this.lhs.computeConversion(scope, lhsType, lhsType);
if (this.typeArguments != null) {
int length = this.typeArguments.length;
this.typeArgumentsHaveErrors = compilerOptions.sourceLevel < ClassFileConstants.JDK1_5;
this.resolvedTypeArguments = new TypeBinding[length];
for (int i = 0; i < length; i++) {
TypeReference typeReference = this.typeArguments[i];
if ((this.resolvedTypeArguments[i] = typeReference.resolveType(scope, true )) == null) {
this.typeArgumentsHaveErrors = true;
}
if (this.typeArgumentsHaveErrors && typeReference instanceof Wildcard) {
scope.problemReporter().illegalUsageOfWildcard(typeReference);
}
}
if (this.typeArgumentsHaveErrors || lhsType == null)
return this.resolvedType = null;
if (isConstructorReference() && lhsType.isRawType()) {
scope.problemReporter().rawConstructorReferenceNotWithExplicitTypeArguments(this.typeArguments);
return this.resolvedType = null;
}
}
if (this.typeArgumentsHaveErrors || lhsType == null)
return this.resolvedType = null;
if (lhsType.problemId() == ProblemReasons.AttemptToBypassDirectSuper)
lhsType = lhsType.closestMatch();
if (lhsType == null || !lhsType.isValidBinding())
return this.resolvedType = null;
this.receiverType = lhsType;
this.haveReceiver = true;
if (this.lhs instanceof NameReference) {
if ((this.lhs.bits & ASTNode.RestrictiveFlagMASK) == Binding.TYPE) {
this.haveReceiver = false;
} else if (isConstructorReference()) {
scope.problemReporter().invalidType(
this.lhs,
new ProblemReferenceBinding(((NameReference) this.lhs).getName(), null,
ProblemReasons.NotFound));
return this.resolvedType = null;
}
} else if (this.lhs instanceof TypeReference) {
this.haveReceiver = false;
}
if (!this.haveReceiver && !this.lhs.isSuper() && !this.isArrayConstructorReference())
this.receiverType = lhsType.capture(scope, this.sourceStart, this.sourceEnd);
if (!lhsType.isRawType())
this.binding = this.exactMethodBinding = isMethodReference() ? scope.getExactMethod(lhsType, this.selector, this) : scope.getExactConstructor(lhsType, this);
if (isConstructorReference() && !lhsType.canBeInstantiated()) {
scope.problemReporter().cannotInstantiate(this.lhs, lhsType);
return this.resolvedType = null;
}
if (this.lhs instanceof TypeReference && ((TypeReference)this.lhs).hasNullTypeAnnotation(AnnotationPosition.ANY)) {
scope.problemReporter().nullAnnotationUnsupportedLocation((TypeReference) this.lhs);
}
if (isConstructorReference() && lhsType.isArrayType()) {
final TypeBinding leafComponentType = lhsType.leafComponentType();
if (!leafComponentType.isReifiable()) {
scope.problemReporter().illegalGenericArray(leafComponentType, this);
return this.resolvedType = null;
}
if (this.typeArguments != null) {
scope.problemReporter().invalidTypeArguments(this.typeArguments);
return this.resolvedType = null;
}
this.binding = this.exactMethodBinding = scope.getExactConstructor(lhsType, this);
}
if (isMethodReference() && this.haveReceiver && (this.original == this)) {
this.receiverVariable = new LocalVariableBinding(
(SecretReceiverVariableName + this.nameSourceStart).toCharArray(), this.lhs.resolvedType,
ClassFileConstants.AccDefault, false);
scope.addLocalVariable(this.receiverVariable);
this.receiverVariable.setConstant(Constant.NotAConstant);
this.receiverVariable.useFlag = LocalVariableBinding.USED;
}
if (this.expectedType == null && this.expressionContext == INVOCATION_CONTEXT) {
if (compilerOptions.isAnnotationBasedNullAnalysisEnabled && this.binding != null) {
ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(this.binding, scope);
}
return new PolyTypeBinding(this);
}
} else {
lhsType = this.lhs.resolvedType;
if (this.typeArgumentsHaveErrors || lhsType == null)
return this.resolvedType = null;
}
super.resolveType(scope);
if (this.descriptor == null || !this.descriptor.isValidBinding())
return this.resolvedType = null;
TypeBinding[] descriptorParameters = descriptorParametersAsArgumentExpressions();
if (lhsType.isBaseType()) {
scope.problemReporter().errorNoMethodFor(this.lhs, lhsType, this.selector, descriptorParameters);
return this.resolvedType = null;
}
final int parametersLength = descriptorParameters.length;
if (isConstructorReference() && lhsType.isArrayType()) {
if (parametersLength != 1 || scope.parameterCompatibilityLevel(descriptorParameters[0], TypeBinding.INT) == Scope.NOT_COMPATIBLE) {
scope.problemReporter().invalidArrayConstructorReference(this, lhsType, descriptorParameters);
return this.resolvedType = null;
}
if (this.descriptor.returnType.isProperType(true) && !lhsType.isCompatibleWith(this.descriptor.returnType) && this.descriptor.returnType.id != TypeIds.T_void) {
scope.problemReporter().constructedArrayIncompatible(this, lhsType, this.descriptor.returnType);
return this.resolvedType = null;
}
checkNullAnnotations(scope);
return this.resolvedType;
}
final boolean isMethodReference = isMethodReference();
this.depth = 0;
this.freeParameters = descriptorParameters;
MethodBinding someMethod = null;
if (isMethodReference) {
someMethod = scope.getMethod(this.receiverType, this.selector, descriptorParameters, this);
} else {
if (argumentsTypeElided() && this.receiverType.isRawType()) {
boolean[] inferredReturnType = new boolean[1];
someMethod = AllocationExpression.inferDiamondConstructor(scope, this, this.receiverType, this.descriptor.parameters, inferredReturnType);
}
if (someMethod == null)
someMethod = scope.getConstructor((ReferenceBinding) this.receiverType, descriptorParameters, this);
}
int someMethodDepth = this.depth, anotherMethodDepth = 0;
if (someMethod != null && someMethod.isValidBinding()) {
if (someMethod.isStatic() && (this.haveReceiver || this.receiverType.isParameterizedTypeWithActualArguments())) {
scope.problemReporter().methodMustBeAccessedStatically(this, someMethod);
return this.resolvedType = null;
}
}
if (this.lhs.isSuper() && this.lhs.resolvedType.isInterface()) {
scope.checkAppropriateMethodAgainstSupers(this.selector, someMethod, this.descriptor.parameters, this);
}
MethodBinding anotherMethod = null;
this.receiverPrecedesParameters = false;
if (!this.haveReceiver && isMethodReference && parametersLength > 0) {
final TypeBinding potentialReceiver = descriptorParameters[0];
if (potentialReceiver.isCompatibleWith(this.receiverType, scope)) {
TypeBinding typeToSearch = this.receiverType;
if (this.receiverType.isRawType()) {
TypeBinding superType = potentialReceiver.findSuperTypeOriginatingFrom(this.receiverType);
if (superType != null)
typeToSearch = superType.capture(scope, this.sourceStart, this.sourceEnd);
}
TypeBinding [] parameters = Binding.NO_PARAMETERS;
if (parametersLength > 1) {
parameters = new TypeBinding[parametersLength - 1];
System.arraycopy(descriptorParameters, 1, parameters, 0, parametersLength - 1);
}
this.depth = 0;
this.freeParameters = parameters;
anotherMethod = scope.getMethod(typeToSearch, this.selector, parameters, this);
anotherMethodDepth = this.depth;
this.depth = 0;
}
}
if (someMethod != null && someMethod.isValidBinding() && someMethod.isStatic() && anotherMethod != null && anotherMethod.isValidBinding() && !anotherMethod.isStatic()) {
scope.problemReporter().methodReferenceSwingsBothWays(this, anotherMethod, someMethod);
return this.resolvedType = null;
}
if (someMethod != null && someMethod.isValidBinding() && (anotherMethod == null || !anotherMethod.isValidBinding() || anotherMethod.isStatic())) {
this.binding = someMethod;
this.bits &= ~ASTNode.DepthMASK;
if (someMethodDepth > 0) {
this.bits |= (someMethodDepth & 0xFF) << ASTNode.DepthSHIFT;
}
if (!this.haveReceiver) {
if (!someMethod.isStatic() && !someMethod.isConstructor()) {
scope.problemReporter().methodMustBeAccessedWithInstance(this, someMethod);
return this.resolvedType = null;
}
}
} else if (anotherMethod != null && anotherMethod.isValidBinding() && (someMethod == null || !someMethod.isValidBinding() || !someMethod.isStatic())) {
this.binding = anotherMethod;
this.receiverPrecedesParameters = true;
this.bits &= ~ASTNode.DepthMASK;
if (anotherMethodDepth > 0) {
this.bits |= (anotherMethodDepth & 0xFF) << ASTNode.DepthSHIFT;
}
if (anotherMethod.isStatic()) {
scope.problemReporter().methodMustBeAccessedStatically(this, anotherMethod);
return this.resolvedType = null;
}
} else {
this.binding = null;
this.bits &= ~ASTNode.DepthMASK;
}
if (this.binding == null) {
char [] visibleName = isConstructorReference() ? this.receiverType.sourceName() : this.selector;
scope.problemReporter().danglingReference(this, this.receiverType, visibleName, descriptorParameters);
return this.resolvedType = null;
}
if (this.binding.isAbstract() && this.lhs.isSuper())
scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, this.binding);
if (this.binding.isStatic()) {
if (TypeBinding.notEquals(this.binding.declaringClass, this.receiverType))
scope.problemReporter().indirectAccessToStaticMethod(this, this.binding);
} else {
AbstractMethodDeclaration srcMethod = this.binding.sourceMethod();
if (srcMethod != null && srcMethod.isMethod())
srcMethod.bits &= ~ASTNode.CanBeStatic;
}
if (isMethodUseDeprecated(this.binding, scope, true, this))
scope.problemReporter().deprecatedMethod(this.binding, this);
if (this.typeArguments != null && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES)
scope.problemReporter().unnecessaryTypeArgumentsForMethodInvocation(this.binding, this.resolvedTypeArguments, this.typeArguments);
if ((this.binding.tagBits & TagBits.HasMissingType) != 0)
scope.problemReporter().missingTypeInMethod(this, this.binding);
TypeBinding [] methodExceptions = this.binding.thrownExceptions;
TypeBinding [] kosherExceptions = this.descriptor.thrownExceptions;
next: for (int i = 0, iMax = methodExceptions.length; i < iMax; i++) {
if (methodExceptions[i].isUncheckedException(false)) {
continue next;
}
for (int j = 0, jMax = kosherExceptions.length; j < jMax; j++) {
if (methodExceptions[i].isCompatibleWith(kosherExceptions[j], scope))
continue next;
}
scope.problemReporter().unhandledException(methodExceptions[i], this);
}
checkNullAnnotations(scope);
this.freeParameters = null;
if (checkInvocationArguments(scope, null, this.receiverType, this.binding, null, descriptorParameters, false, this))
this.bits |= ASTNode.Unchecked;
if (this.descriptor.returnType.id != TypeIds.T_void) {
TypeBinding returnType = null;
if (this.binding.isConstructor()) {
returnType = this.receiverType;
} else {
if ((this.bits & ASTNode.Unchecked) != 0 && this.resolvedTypeArguments == null) {
returnType = this.binding.returnType;
if (returnType != null) {
returnType = scope.environment().convertToRawType(returnType.erasure(), true);
}
} else {
returnType = this.binding.returnType;
if (returnType != null) {
returnType = returnType.capture(scope, this.sourceStart, this.sourceEnd);
}
}
}
if (this.descriptor.returnType.isProperType(true)
&& !returnType.isCompatibleWith(this.descriptor.returnType, scope)
&& !isBoxingCompatible(returnType, this.descriptor.returnType, this, scope))
{
scope.problemReporter().incompatibleReturnType(this, this.binding, this.descriptor.returnType);
this.binding = null;
this.resolvedType = null;
}
}
return this.resolvedType;
}
protected void checkNullAnnotations(BlockScope scope) {
CompilerOptions compilerOptions = scope.compilerOptions();
if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) {
if (this.expectedType == null || !NullAnnotationMatching.hasContradictions(this.expectedType)) {
ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(this.binding, scope);
int len;
int expectedlen = this.binding.parameters.length;
int providedLen = this.descriptor.parameters.length;
if (this.receiverPrecedesParameters) {
providedLen--;
TypeBinding descriptorParameter = this.descriptor.parameters[0];
if((descriptorParameter.tagBits & TagBits.AnnotationNullable) != 0) {
final TypeBinding receiver = scope.environment().createAnnotatedType(this.binding.declaringClass,
new AnnotationBinding[] { scope.environment().getNonNullAnnotation() });
scope.problemReporter().referenceExpressionArgumentNullityMismatch(this, receiver, descriptorParameter, this.descriptor, -1, NullAnnotationMatching.NULL_ANNOTATIONS_MISMATCH);
}
}
boolean isVarArgs = false;
if (this.binding.isVarargs()) {
isVarArgs = (providedLen == expectedlen)
? !this.descriptor.parameters[expectedlen-1].isCompatibleWith(this.binding.parameters[expectedlen-1])
: true;
len = providedLen;
} else {
len = Math.min(expectedlen, providedLen);
}
for (int i = 0; i < len; i++) {
TypeBinding descriptorParameter = this.descriptor.parameters[i + (this.receiverPrecedesParameters ? 1 : 0)];
TypeBinding bindingParameter = InferenceContext18.getParameter(this.binding.parameters, i, isVarArgs);
TypeBinding bindingParameterToCheck;
if (bindingParameter.isPrimitiveType() && !descriptorParameter.isPrimitiveType()) {
bindingParameterToCheck = scope.environment().createAnnotatedType(scope.boxing(bindingParameter),
new AnnotationBinding[] { scope.environment().getNonNullAnnotation() });
} else {
bindingParameterToCheck = bindingParameter;
}
NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(bindingParameterToCheck, descriptorParameter, FlowInfo.UNKNOWN);
if (annotationStatus.isAnyMismatch()) {
scope.problemReporter().referenceExpressionArgumentNullityMismatch(this, bindingParameter, descriptorParameter, this.descriptor, i, annotationStatus);
}
}
TypeBinding returnType = this.binding.returnType;
if(!returnType.isPrimitiveType()) {
if (this.binding.isConstructor()) {
returnType = scope.environment().createAnnotatedType(this.receiverType, new AnnotationBinding[]{ scope.environment().getNonNullAnnotation() });
}
NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(this.descriptor.returnType, returnType, FlowInfo.UNKNOWN);
if (annotationStatus.isAnyMismatch()) {
scope.problemReporter().illegalReturnRedefinition(this, this.descriptor, annotationStatus.isUnchecked(), returnType);
}
}
}
}
}
private TypeBinding[] descriptorParametersAsArgumentExpressions() {
if (this.descriptor == null || this.descriptor.parameters == null || this.descriptor.parameters.length == 0)
return Binding.NO_PARAMETERS;
if (this.expectedType.isParameterizedType()) {
ParameterizedTypeBinding type = (ParameterizedTypeBinding) this.expectedType;
MethodBinding method = type.getSingleAbstractMethod(this.enclosingScope, true, this.sourceStart, this.sourceEnd);
return method.parameters;
}
return this.descriptor.parameters;
}
private ReferenceExpression cachedResolvedCopy(TypeBinding targetType) {
ReferenceExpression copy = this.copiesPerTargetType != null ? this.copiesPerTargetType.get(targetType) : null;
if (copy != null)
return copy;
IErrorHandlingPolicy oldPolicy = this.enclosingScope.problemReporter().switchErrorHandlingPolicy(silentErrorHandlingPolicy);
try {
copy = copy();
if (copy == null) {
return null;
}
copy.setExpressionContext(this.expressionContext);
copy.setExpectedType(targetType);
copy.resolveType(this.enclosingScope);
if (this.copiesPerTargetType == null)
this.copiesPerTargetType = new HashMap<TypeBinding, ReferenceExpression>();
this.copiesPerTargetType.put(targetType, copy);
return copy;
} finally {
this.enclosingScope.problemReporter().switchErrorHandlingPolicy(oldPolicy);
}
}
public void registerInferenceContext(ParameterizedGenericMethodBinding method, InferenceContext18 context) {
if (this.inferenceContexts == null)
this.inferenceContexts = new HashMap<ParameterizedGenericMethodBinding, InferenceContext18>();
this.inferenceContexts.put(method, context);
}
public InferenceContext18 getInferenceContext(ParameterizedMethodBinding method) {
if (this.inferenceContexts == null)
return null;
return this.inferenceContexts.get(method);
}
@Override
public ReferenceExpression resolveExpressionExpecting(TypeBinding targetType, Scope scope, InferenceContext18 inferenceContext) {
if (this.exactMethodBinding != null) {
MethodBinding functionType = targetType.getSingleAbstractMethod(scope, true);
if (functionType == null || functionType.problemId() == ProblemReasons.NoSuchSingleAbstractMethod)
return null;
int n = functionType.parameters.length;
int k = this.exactMethodBinding.parameters.length;
if (!this.haveReceiver && this.isMethodReference() && !this.exactMethodBinding.isStatic()) {
k++;
}
return (n == k) ? this : null;
}
ReferenceExpression copy = cachedResolvedCopy(targetType);
return copy != null && copy.resolvedType != null && copy.resolvedType.isValidBinding() && copy.binding != null && copy.binding.isValidBinding() ? copy : null;
}
public boolean isConstructorReference() {
return CharOperation.equals(this.selector, ConstantPool.Init);
}
@Override
public boolean isExactMethodReference() {
return this.exactMethodBinding != null;
}
public MethodBinding getExactMethod() {
return this.exactMethodBinding;
}
public boolean isMethodReference() {
return !CharOperation.equals(this.selector, ConstantPool.Init);
}
@Override
public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) {
if (!this.isExactMethodReference()) {
return false;
}
return super.isPertinentToApplicability(targetType, method);
}
@Override
public TypeBinding[] genericTypeArguments() {
return this.resolvedTypeArguments;
}
@Override
public InferenceContext18 freshInferenceContext(Scope scope) {
if (this.expressionContext != ExpressionContext.VANILLA_CONTEXT) {
Expression[] arguments = createPseudoExpressions(this.freeParameters);
return new InferenceContext18(scope, arguments, this, null);
}
return null;
}
@Override
public boolean isSuperAccess() {
return this.lhs.isSuper();
}
@Override
public boolean isTypeAccess() {
return !this.haveReceiver;
}
@Override
public void setActualReceiverType(ReferenceBinding receiverType) {
return;
}
@Override
public void setDepth(int depth) {
this.depth = depth;
}
@Override
public void setFieldIndex(int depth) {
return;
}
@Override
public StringBuffer printExpression(int tab, StringBuffer output) {
this.lhs.print(0, output);
output.append("::");
if (this.typeArguments != null) {
output.append('<');
int max = this.typeArguments.length - 1;
for (int j = 0; j < max; j++) {
this.typeArguments[j].print(0, output);
output.append(", ");
}
this.typeArguments[max].print(0, output);
output.append('>');
}
if (isConstructorReference())
output.append("new");
else
output.append(this.selector);
return output;
}
@Override
public void traverse(ASTVisitor visitor, BlockScope blockScope) {
if (visitor.visit(this, blockScope)) {
this.lhs.traverse(visitor, blockScope);
int length = this.typeArguments == null ? 0 : this.typeArguments.length;
for (int i = 0; i < length; i++) {
this.typeArguments[i].traverse(visitor, blockScope);
}
}
visitor.endVisit(this, blockScope);
}
public Expression[] createPseudoExpressions(TypeBinding[] p) {
Expression[] expressions = new Expression[p.length];
long pos = (((long)this.sourceStart)<<32)+this.sourceEnd;
for (int i = 0; i < p.length; i++) {
expressions[i] = new SingleNameReference(("fakeArg"+i).toCharArray(), pos);
expressions[i].resolvedType = p[i];
}
return expressions;
}
@Override
public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope scope) {
final boolean isConstructorRef = isConstructorReference();
if (isConstructorRef) {
if (this.receiverType == null)
return false;
if (this.receiverType.isArrayType()) {
final TypeBinding leafComponentType = this.receiverType.leafComponentType();
if (!leafComponentType.isReifiable()) {
return false;
}
}
}
if (!super.isPertinentToApplicability(targetType, null))
return true;
final MethodBinding sam = targetType.getSingleAbstractMethod(this.enclosingScope, true);
if (sam == null || !sam.isValidBinding())
return false;
if (this.typeArgumentsHaveErrors || this.receiverType == null || !this.receiverType.isValidBinding())
return false;
int parametersLength = sam.parameters.length;
TypeBinding[] descriptorParameters = new TypeBinding[parametersLength];
for (int i = 0; i < parametersLength; i++) {
descriptorParameters[i] = new ReferenceBinding() {
{
this.compoundName = CharOperation.NO_CHAR_CHAR;
}
@Override
public boolean isCompatibleWith(TypeBinding otherType, Scope captureScope) {
return true;
}
@Override
public TypeBinding findSuperTypeOriginatingFrom(TypeBinding otherType) {
return otherType;
}
@Override
public String toString() {
return "(wildcard)";
}
};
}
this.freeParameters = descriptorParameters;
this.checkingPotentialCompatibility = true;
try {
MethodBinding compileTimeDeclaration = getCompileTimeDeclaration(scope, isConstructorRef, descriptorParameters);
if (compileTimeDeclaration != null && compileTimeDeclaration.isValidBinding())
this.potentialMethods = new MethodBinding [] { compileTimeDeclaration };
else {
}
for (int i = 0, length = this.potentialMethods.length; i < length; i++) {
if (this.potentialMethods[i].isStatic() || this.potentialMethods[i].isConstructor()) {
if (!this.haveReceiver)
return true;
} else {
if (this.haveReceiver)
return true;
}
}
if (this.haveReceiver || parametersLength == 0)
return false;
System.arraycopy(descriptorParameters, 1, descriptorParameters = new TypeBinding[parametersLength - 1], 0, parametersLength - 1);
this.freeParameters = descriptorParameters;
this.potentialMethods = Binding.NO_METHODS;
compileTimeDeclaration = getCompileTimeDeclaration(scope, false, descriptorParameters);
if (compileTimeDeclaration != null && compileTimeDeclaration.isValidBinding())
this.potentialMethods = new MethodBinding [] { compileTimeDeclaration };
else {
}
for (int i = 0, length = this.potentialMethods.length; i < length; i++) {
if (!this.potentialMethods[i].isStatic() && !this.potentialMethods[i].isConstructor()) {
return true;
}
}
} finally {
this.checkingPotentialCompatibility = false;
this.potentialMethods = Binding.NO_METHODS;
this.freeParameters = null;
}
return false;
}
MethodBinding getCompileTimeDeclaration(Scope scope, boolean isConstructorRef, TypeBinding[] parameters) {
if (this.exactMethodBinding != null)
return this.exactMethodBinding;
else if (this.receiverType.isArrayType())
return scope.findMethodForArray((ArrayBinding) this.receiverType, this.selector, Binding.NO_PARAMETERS, this);
else if (isConstructorRef)
return scope.getConstructor((ReferenceBinding) this.receiverType, parameters, this);
else
return scope.getMethod(this.receiverType, this.selector, parameters, this);
}
@Override
public boolean isCompatibleWith(TypeBinding targetType, Scope scope) {
ReferenceExpression copy = cachedResolvedCopy(targetType);
return copy != null && copy.resolvedType != null && copy.resolvedType.isValidBinding() && copy.binding != null && copy.binding.isValidBinding();
}
@Override
public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope scope) {
if (super.sIsMoreSpecific(s, t, scope))
return true;
if (this.exactMethodBinding == null || t.findSuperTypeOriginatingFrom(s) != null)
return false;
s = s.capture(this.enclosingScope, this.sourceStart, this.sourceEnd);
MethodBinding sSam = s.getSingleAbstractMethod(this.enclosingScope, true);
if (sSam == null || !sSam.isValidBinding())
return false;
TypeBinding r1 = sSam.returnType;
MethodBinding tSam = t.getSingleAbstractMethod(this.enclosingScope, true);
if (tSam == null || !tSam.isValidBinding())
return false;
TypeBinding r2 = tSam.returnType;
TypeBinding[] sParams = sSam.parameters;
TypeBinding[] tParams = tSam.parameters;
for (int i = 0; i < sParams.length; i++) {
if (TypeBinding.notEquals(sParams[i], tParams[i]))
return false;
}
if (r2.id == TypeIds.T_void)
return true;
if (r1.id == TypeIds.T_void)
return false;
if (r1.isCompatibleWith(r2, scope))
return true;
return r1.isBaseType() != r2.isBaseType() && r1.isBaseType() == this.exactMethodBinding.returnType.isBaseType();
}
@Override
public org.eclipse.jdt.internal.compiler.lookup.MethodBinding getMethodBinding() {
if (this.actualMethodBinding == null)
this.actualMethodBinding = this.binding;
return this.actualMethodBinding;
}
public boolean isArrayConstructorReference() {
return isConstructorReference() && this.lhs.resolvedType != null && this.lhs.resolvedType.isArrayType();
}
}