### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java,v retrieving revision 1.88 diff -u -r1.88 Assignment.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 7 Mar 2009 00:58:57 -0000 1.88 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 14 Apr 2009 10:04:45 -0000 @@ -154,7 +154,15 @@ if (lhsType != null) { this.resolvedType = lhsType.capture(scope, this.sourceEnd); } - TypeBinding rhsType = this.expression.resolveType(scope); + TypeBinding rhsType ; + if(this.expression instanceof BinaryExpression){ + BinaryExpression bin=(BinaryExpression)this.expression; + bin.operatorOverloader=true; + rhsType= this.expression.resolveType(scope); + if(rhsType!=null && bin.messageSend !=null) + this.expression = bin.messageSend; + }else + rhsType= this.expression.resolveType(scope); if (lhsType == null || rhsType == null) { return null; } Index: compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java,v retrieving revision 1.68 diff -u -r1.68 BinaryExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java 26 Nov 2008 17:56:55 -0000 1.68 +++ compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java 14 Apr 2009 10:04:47 -0000 @@ -1788,15 +1788,34 @@ return this.right.printExpression(0, output); } +public boolean operatorOverloader; +public MessageSend messageSend; + public TypeBinding resolveType(BlockScope scope) { // keep implementation in sync with CombinedBinaryExpression#resolveType // and nonRecursiveResolveTypeUpwards boolean leftIsCast, rightIsCast; if ((leftIsCast = this.left instanceof CastExpression) == true) this.left.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on - TypeBinding leftType = this.left.resolveType(scope); + TypeBinding leftType; + if(this.left instanceof BinaryExpression){ + BinaryExpression bin=(BinaryExpression)this.left; + bin.operatorOverloader=true; + leftType= this.left.resolveType(scope); + if(leftType!=null && bin.messageSend !=null) + this.left= bin.messageSend; + }else + leftType = this.left.resolveType(scope); if ((rightIsCast = this.right instanceof CastExpression) == true) this.right.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on - TypeBinding rightType = this.right.resolveType(scope); + TypeBinding rightType; + if(this.right instanceof BinaryExpression){ + BinaryExpression bin=(BinaryExpression)this.right; + bin.operatorOverloader=true; + rightType= this.right.resolveType(scope); + if(rightType!=null && bin.messageSend !=null) + this.right= bin.messageSend; + }else + rightType = this.right.resolveType(scope); // use the id of the type to navigate into the table if (leftType == null || rightType == null) { @@ -1817,6 +1836,7 @@ rightTypeID = scope.environment().computeBoxingType(rightType).id; } } + int operator = (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT; if (leftTypeID > 15 || rightTypeID > 15) { // must convert String + Object || Object + String if (leftTypeID == TypeIds.T_JavaLangString) { @@ -1824,12 +1844,23 @@ } else if (rightTypeID == TypeIds.T_JavaLangString) { leftTypeID = TypeIds.T_JavaLangObject; } else { + if(this.operatorOverloader && (operator==PLUS || operator==MINUS || operator==MULTIPLY || operator==DIVIDE)){ + this.messageSend=new Expression2MessageSend(this, leftType, rightType); +// this.messageSend.expectedType = expectedType; + TypeBinding resolveType = this.messageSend.resolveType(scope); + if(resolveType!=null){ + return resolveType; + } + this.messageSend = null; + this.operatorOverloader = false; + //continue to old process + } this.constant = Constant.NotAConstant; scope.problemReporter().invalidOperator(this, leftType, rightType); return null; } } - if (((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS) { + if (operator == OperatorIds.PLUS) { if (leftTypeID == TypeIds.T_JavaLangString) { this.left.computeConversion(scope, leftType, leftType); if (rightType.isArrayType() && ((ArrayBinding) rightType).elementsType() == TypeBinding.CHAR) { @@ -1851,7 +1882,6 @@ // Don't test for result = 0. If it is zero, some more work is done. // On the one hand when it is not zero (correct code) we avoid doing the test - int operator = (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT; int operatorSignature = OperatorExpression.OperatorSignatures[operator][(leftTypeID << 4) + rightTypeID]; this.left.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), leftType); Index: compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java,v retrieving revision 1.144 diff -u -r1.144 MessageSend.java --- compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 19 Feb 2009 18:54:57 -0000 1.144 +++ compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 14 Apr 2009 10:04:47 -0000 @@ -354,7 +354,15 @@ argument.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on argsContainCast = true; } - if ((argumentTypes[i] = argument.resolveType(scope)) == null){ + if(argument instanceof BinaryExpression){ + BinaryExpression bin=(BinaryExpression)argument; + bin.operatorOverloader=true; + argumentTypes[i]= argument.resolveType(scope); + if(argumentTypes[i]!=null && bin.messageSend !=null) + this.arguments[i] = bin.messageSend; + }else + argumentTypes[i] = argument.resolveType(scope); + if (argumentTypes[i] == null){ argHasError = true; } } Index: compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java,v retrieving revision 1.103 diff -u -r1.103 AbstractMethodDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java 7 Mar 2009 01:08:07 -0000 1.103 +++ compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java 14 Apr 2009 10:04:45 -0000 @@ -161,17 +161,21 @@ int problemResetPC = 0; classFile.codeStream.wideMode = false; // reset wideMode to false - if (this.ignoreFurtherInvestigation) { + if (this.ignoreFurtherInvestigation ){ + //this.scope.referenceCompilationUnit().compilationResult.firstErrors.size()>0) { // method is known to have errors, dump a problem method if (this.binding == null) return; // handle methods with invalid signature or duplicates - int problemsLength; - CategorizedProblem[] problems = - this.scope.referenceCompilationUnit().compilationResult.getProblems(); - CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length]; - System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); - classFile.addProblemMethod(this, this.binding, problemsCopy); - return; + //TODO: at here should reference problement count instead of problems.length + if(this.scope.referenceCompilationUnit().compilationResult.problemCount>0){ + int problemsLength; + CategorizedProblem[] problems = + this.scope.referenceCompilationUnit().compilationResult.getProblems(); + CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length]; + System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); + classFile.addProblemMethod(this, this.binding, problemsCopy); + return; + } } // regular code generation try { @@ -441,10 +445,84 @@ } public void resolveStatements() { - + Statement statement; if (this.statements != null) { for (int i = 0, length = this.statements.length; i < length; i++) { - this.statements[i].resolve(this.scope); + statement = this.statements[i]; + if(statement instanceof Assignment){ + //check Syntax Error problem + //Expression2MessageSend.findProblem(this.scope) + //in this context the compilationResult2 == this.compilationResult + CompilationResult compilationResult2=this.compilationResult; + //this.scope.compilationUnitScope().referenceContext().compilationResult(); + int count=compilationResult2.problemCount; + if(count>0){ + CategorizedProblem[] problems = compilationResult2.problems; + CategorizedProblem problem, syntaxProblem=null; + int sourcePosition; + int problemIndex=-1; + char[] replaceSelector = null; + for(int pi=0;pi-1 && replaceSelector!=null){ + Assignment assignment = (Assignment)statement; + MessageSend m=new MessageSend(); + m.receiver = assignment.lhs; + m.selector = replaceSelector; + m.arguments = new Expression[]{assignment.expression}; + this.statements[i] = m; + statement = m; + m.sourceStart = assignment.sourceStart; + m.sourceEnd = assignment.sourceEnd; + m.statementEnd = assignment.statementEnd; + //remove syntax error problem from the CompilationResult + compilationResult2.problemsMap.remove(syntaxProblem); + compilationResult2.firstErrors.remove(syntaxProblem); + count = compilationResult2.problemCount-1; + if(count> problemIndex){ + System.arraycopy(compilationResult2.problems, problemIndex+1, // + compilationResult2.problems, problemIndex, count-problemIndex); + compilationResult2.problems[count] = null; + } + else + compilationResult2.problems[problemIndex] = null; + compilationResult2.problemCount=count; + if(compilationResult2.hasSyntaxError && compilationResult2.firstErrors.isEmpty() ) + compilationResult2.hasSyntaxError=false; + if(count==0 && this.ignoreFurtherInvestigation){ + this.ignoreFurtherInvestigation = false; +// compilationResult2. +// ReferenceContext referenceContext = this.scope.compilationUnitScope().referenceContext(); +// if(referenceContext instanceof AbstractMethodDeclaration) +// ((AbstractMethodDeclaration)referenceContext).ignoreFurtherInvestigation = false; + } + } + } + } + statement.resolve(this.scope); } } else if ((this.bits & UndocumentedEmptyBlock) != 0) { this.scope.problemReporter().undocumentedEmptyBlock(this.bodyStart-1, this.bodyEnd+1); Index: compiler/org/eclipse/jdt/internal/compiler/ast/Expression2MessageSend.java =================================================================== RCS file: compiler/org/eclipse/jdt/internal/compiler/ast/Expression2MessageSend.java diff -N compiler/org/eclipse/jdt/internal/compiler/ast/Expression2MessageSend.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Expression2MessageSend.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,306 @@ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; +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.MethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; +import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.TagBits; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; +import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; + +/** + * Operator overload implementation prototype. + * + * @author XIANGYA + * @since 0.1 + * @version 0.1 + */ +public class Expression2MessageSend extends MessageSend{ + public final static char[][] DefaultOperatorNames=new char[][]{// + "add".toCharArray(), //$NON-NLS-1$ + "subtract".toCharArray(),//$NON-NLS-1$ + "multiply".toCharArray(),//$NON-NLS-1$ + "divide".toCharArray(),//$NON-NLS-1$ + }; + + private TypeBinding[] resolvedArgumentTypes; + public Expression2MessageSend(BinaryExpression binaryExpression, TypeBinding leftType, TypeBinding rightType) { + this.receiver = binaryExpression.left; + switch((binaryExpression.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT){ + case OperatorIds.PLUS: + this.selector = DefaultOperatorNames[0]; + break; + case OperatorIds.MINUS: + this.selector = DefaultOperatorNames[1]; + break; + case OperatorIds.MULTIPLY: + this.selector = DefaultOperatorNames[2]; + break; + case OperatorIds.DIVIDE: + this.selector = DefaultOperatorNames[3]; + break; + } + this.arguments = new Expression[] { binaryExpression.right }; + this.sourceStart = binaryExpression.sourceStart; + this.sourceEnd = binaryExpression.sourceEnd; + this.actualReceiverType = leftType; + this.resolvedArgumentTypes = new TypeBinding[]{rightType}; + } + + public TypeBinding resolveType(BlockScope scope) { + + // Answer the signature return type + // Base type promotion + + this.constant = Constant.NotAConstant; + boolean receiverCast = false, argsContainCast = false; + if (this.receiver instanceof CastExpression) { + this.receiver.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on + receiverCast = true; + } + //this.actualReceiverType = this.receiver.resolveType(scope); + boolean receiverIsType = this.receiver instanceof NameReference && (((NameReference) this.receiver).bits & Binding.TYPE) != 0; + if (receiverCast && this.actualReceiverType != null) { + // due to change of declaring class with receiver type, only identity cast should be notified + if (((CastExpression)this.receiver).expression.resolvedType == this.actualReceiverType) { + return null; + //scope.problemReporter().unnecessaryCast((CastExpression)this.receiver); + } + } + // resolve type arguments (for generic constructor call) + if (this.typeArguments != null) { + int length = this.typeArguments.length; + boolean argHasError = scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_5; // typeChecks all arguments + this.genericTypeArguments = new TypeBinding[length]; + for (int i = 0; i < length; i++) { + TypeReference typeReference = this.typeArguments[i]; + if ((this.genericTypeArguments[i] = typeReference.resolveType(scope, true /* check bounds*/)) == null) { + argHasError = true; + } + if (argHasError && typeReference instanceof Wildcard) { + return null; + //scope.problemReporter().illegalUsageOfWildcard(typeReference); + } + } + if (argHasError) { + if (this.arguments != null) { // still attempt to resolve arguments + for (int i = 0, max = this.arguments.length; i < max; i++) { + this.arguments[i].resolveType(scope); + } + } + return null; + } + } + // will check for null after args are resolved +// TypeBinding[] argumentTypes = Binding.NO_PARAMETERS; + TypeBinding[] argumentTypes = this.resolvedArgumentTypes; + if (this.arguments != null) { +// boolean argHasError = false; // typeChecks all arguments + int length = this.arguments.length; + boolean argHasError = this.resolvedArgumentTypes[0]==null; +// argumentTypes = new TypeBinding[length]; +// for (int i = 0; i < length; i++){ +// Expression argument = this.arguments[i]; +// if (argument instanceof CastExpression) { +// argument.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on +// argsContainCast = true; +// } +// if ((argumentTypes[i] = argument.resolveType(scope)) == null){ +// argHasError = true; +// } +// } + if (argHasError) { + if (this.actualReceiverType instanceof ReferenceBinding) { + // record a best guess, for clients who need hint about possible method match + TypeBinding[] pseudoArgs = new TypeBinding[length]; + for (int i = length; --i >= 0;) + pseudoArgs[i] = argumentTypes[i] == null ? TypeBinding.NULL : argumentTypes[i]; // replace args with errors with null type + this.binding = + this.receiver.isImplicitThis() + ? scope.getImplicitMethod(this.selector, pseudoArgs, this) + : scope.findMethod((ReferenceBinding) this.actualReceiverType, this.selector, pseudoArgs, this); + if (this.binding != null && !this.binding.isValidBinding()) { + MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; + // record the closest match, for clients who may still need hint about possible method match + if (closestMatch != null) { + if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { // generic method + // shouldn't return generic method outside its context, rather convert it to raw method (175409) + closestMatch = scope.environment().createParameterizedGenericMethod(closestMatch.original(), (RawTypeBinding)null); + } + this.binding = closestMatch; + MethodBinding closestMatchOriginal = closestMatch.original(); + if (closestMatchOriginal.isOrEnclosedByPrivateType() && !scope.isDefinedInMethod(closestMatchOriginal)) { + // ignore cases where method is used from within inside itself (e.g. direct recursions) + closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; + } + } + } + } + return null; + } + } + if (this.actualReceiverType == null) { + return null; + } + // base type cannot receive any message + if (this.actualReceiverType.isBaseType()) { + return null; + // scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes); + } + this.binding = this.receiver.isImplicitThis() + ? scope.getImplicitMethod(this.selector, argumentTypes, this) + : scope.getMethod(this.actualReceiverType, this.selector, argumentTypes, this); + if (!this.binding.isValidBinding()) { + if (this.binding.declaringClass == null) { + if (this.actualReceiverType instanceof ReferenceBinding) { + this.binding.declaringClass = (ReferenceBinding) this.actualReceiverType; + } else { + return null; +// scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes); + } + } + scope.problemReporter().invalidMethod(this, this.binding); + MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; + switch (this.binding.problemId()) { + case ProblemReasons.Ambiguous : + break; // no resilience on ambiguous + case ProblemReasons.NotVisible : + case ProblemReasons.NonStaticReferenceInConstructorInvocation : + case ProblemReasons.NonStaticReferenceInStaticContext : + case ProblemReasons.ReceiverTypeNotVisible : + case ProblemReasons.ParameterBoundMismatch : + // only steal returnType in cases listed above + if (closestMatch != null) this.resolvedType = closestMatch.returnType; + break; + } + // record the closest match, for clients who may still need hint about possible method match + if (closestMatch != null) { + this.binding = closestMatch; + MethodBinding closestMatchOriginal = closestMatch.original(); + if (closestMatchOriginal.isOrEnclosedByPrivateType() && !scope.isDefinedInMethod(closestMatchOriginal)) { + // ignore cases where method is used from within inside itself (e.g. direct recursions) + closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; + } + } + return (this.resolvedType != null && (this.resolvedType.tagBits & TagBits.HasMissingType) == 0) + ? this.resolvedType + : null; + } + if ((this.binding.tagBits & TagBits.HasMissingType) != 0) { + scope.problemReporter().missingTypeInMethod(this, this.binding); + } + final CompilerOptions compilerOptions = scope.compilerOptions(); + if (!this.binding.isStatic()) { + // the "receiver" must not be a type + if (receiverIsType) { + scope.problemReporter().mustUseAStaticMethod(this, this.binding); + if (this.actualReceiverType.isRawType() + && (this.receiver.bits & ASTNode.IgnoreRawTypeCheck) == 0 + && compilerOptions.getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore) { + scope.problemReporter().rawTypeReference(this.receiver, this.actualReceiverType); + } + } else { + // handle indirect inheritance thru variable secondary bound + // receiver may receive generic cast, as part of implicit conversion + TypeBinding oldReceiverType = this.actualReceiverType; + this.actualReceiverType = this.actualReceiverType.getErasureCompatibleType(this.binding.declaringClass); + this.receiver.computeConversion(scope, this.actualReceiverType, this.actualReceiverType); + if (this.actualReceiverType != oldReceiverType && this.receiver.postConversionType(scope) != this.actualReceiverType) { // record need for explicit cast at codegen since receiver could not handle it + this.bits |= NeedReceiverGenericCast; + } + } + } else { + // static message invoked through receiver? legal but unoptimal (optional warning). + if (!(this.receiver.isImplicitThis() || this.receiver.isSuper() || receiverIsType)) { + scope.problemReporter().nonStaticAccessToStaticMethod(this, this.binding); + } + if (!this.receiver.isImplicitThis() && this.binding.declaringClass != this.actualReceiverType) { + scope.problemReporter().indirectAccessToStaticMethod(this, this.binding); + } + } + if (checkInvocationArguments(scope, this.receiver, this.actualReceiverType, this.binding, this.arguments, argumentTypes, argsContainCast, this)) { + this.bits |= ASTNode.Unchecked; + } + + //-------message send that are known to fail at compile time----------- + if (this.binding.isAbstract()) { + if (this.receiver.isSuper()) { + scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, this.binding); + } + // abstract private methods cannot occur nor abstract static............ + } + if (isMethodUseDeprecated(this.binding, scope, true)) + scope.problemReporter().deprecatedMethod(this.binding, this); + + // from 1.5 source level on, array#clone() returns the array type (but binding still shows Object) + if (this.binding == scope.environment().arrayClone && compilerOptions.sourceLevel >= ClassFileConstants.JDK1_5) { + this.resolvedType = this.actualReceiverType; + } else { + TypeBinding returnType; + if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) { + returnType = this.binding.original().returnType; + if (returnType != null) { + returnType = scope.environment().convertToRawType(returnType.erasure(), true); + } + } else { + returnType = this.binding.returnType; + if (returnType != null) { + returnType = returnType.capture(scope, this.sourceEnd); + } + } + this.resolvedType = returnType; + } + if (this.receiver.isSuper() && compilerOptions.getSeverity(CompilerOptions.OverridingMethodWithoutSuperInvocation) != ProblemSeverities.Ignore) { + final ReferenceContext referenceContext = scope.methodScope().referenceContext; + if (referenceContext instanceof AbstractMethodDeclaration) { + final AbstractMethodDeclaration abstractMethodDeclaration = (AbstractMethodDeclaration) referenceContext; + MethodBinding enclosingMethodBinding = abstractMethodDeclaration.binding; + if (enclosingMethodBinding.isOverriding() + && CharOperation.equals(this.binding.selector, enclosingMethodBinding.selector) + && this.binding.areParametersEqual(enclosingMethodBinding)) { + abstractMethodDeclaration.bits |= ASTNode.OverridingMethodWithSupercall; + } + } + } + if (this.typeArguments != null && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) { + scope.problemReporter().unnecessaryTypeArgumentsForMethodInvocation(this.binding, this.genericTypeArguments, this.typeArguments); + } + return (this.resolvedType.tagBits & TagBits.HasMissingType) == 0 + ? this.resolvedType + : null; + } +}