X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Assignment.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Assignment.java index 5f7c560..297f4a0 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Assignment.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/Assignment.java @@ -1,113 +1,188 @@ /******************************************************************************* - * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v0.5 + * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v05.html + * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation - ******************************************************************************/ + * Genady Beriozkin - added support for reporting assignment with no effect + *******************************************************************************/ package net.sourceforge.phpdt.internal.compiler.ast; -import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; -import net.sourceforge.phpdt.internal.compiler.codegen.*; -import net.sourceforge.phpdt.internal.compiler.flow.*; -import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.ASTVisitor; +import net.sourceforge.phpdt.internal.compiler.flow.FlowContext; +import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo; +import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypeBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.Binding; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; public class Assignment extends Expression { - public Reference lhs; + public Expression lhs; + public Expression expression; - public TypeBinding lhsType; - + public Assignment(Expression lhs, Expression expression, int sourceEnd) { - //lhs is always a reference by construction , - //but is build as an expression ==> the checkcast cannot fail + // lhs is always a reference by construction , + // but is build as an expression ==> the checkcast cannot fail + + this.lhs = lhs; + lhs.bits |= IsStrictlyAssignedMASK; // tag lhs as assigned - this.lhs = (Reference) lhs; this.expression = expression; this.sourceStart = lhs.sourceStart; this.sourceEnd = sourceEnd; } - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - // record setting a variable: various scenarii are possible, setting an array reference, - // a field reference, a blank final field reference, a field of an enclosing instance or + public FlowInfo analyseCode(BlockScope currentScope, + FlowContext flowContext, FlowInfo flowInfo) { + // record setting a variable: various scenarii are possible, setting an + // array reference, + // a field reference, a blank final field reference, a field of an + // enclosing instance or // just a local variable. - return lhs - .analyseAssignment(currentScope, flowContext, flowInfo, this, false) - .unconditionalInits(); + return ((Reference) lhs).analyseAssignment(currentScope, flowContext, + flowInfo, this, false).unconditionalInits(); } - public void generateCode( - BlockScope currentScope, - CodeStream codeStream, - boolean valueRequired) { + void checkAssignmentEffect(BlockScope scope) { - // various scenarii are possible, setting an array reference, - // a field reference, a blank final field reference, a field of an enclosing instance or - // just a local variable. + Binding left = getDirectBinding(this.lhs); + if (left != null && left == getDirectBinding(this.expression)) { + scope.problemReporter().assignmentHasNoEffect(this, + left.shortReadableName()); + this.bits |= IsAssignmentWithNoEffectMASK; // record assignment has + // no effect + } + } + + // public void generateCode( + // BlockScope currentScope, + // CodeStream codeStream, + // boolean valueRequired) { + // + // // various scenarii are possible, setting an array reference, + // // a field reference, a blank final field reference, a field of an + // enclosing instance or + // // just a local variable. + // + // int pc = codeStream.position; + // if ((this.bits & IsAssignmentWithNoEffectMASK) != 0) { + // if (valueRequired) { + // this.expression.generateCode(currentScope, codeStream, true); + // } + // } else { + // ((Reference) lhs).generateAssignment(currentScope, codeStream, this, + // valueRequired); + // // variable may have been optimized out + // // the lhs is responsible to perform the implicitConversion generation + // for the assignment since optimized for unused local assignment. + // } + // codeStream.recordPositionsFrom(pc, this.sourceStart); + // } + + Binding getDirectBinding(Expression someExpression) { + if (someExpression instanceof SingleNameReference) { + return ((SingleNameReference) someExpression).binding; + } else if (someExpression instanceof FieldReference) { + FieldReference fieldRef = (FieldReference) someExpression; + if (fieldRef.receiver.isThis() + && !(fieldRef.receiver instanceof QualifiedThisReference)) { + return fieldRef.binding; + } + } + return null; + } + + public StringBuffer print(int indent, StringBuffer output) { + + // no () when used as a statement + printIndent(indent, output); + return printExpressionNoParenthesis(indent, output); + } + + public StringBuffer printExpression(int indent, StringBuffer output) { - int pc = codeStream.position; - lhs.generateAssignment(currentScope, codeStream, this, valueRequired); - // variable may have been optimized out - // the lhs is responsible to perform the implicitConversion generation for the assignment since optimized for unused local assignment. - codeStream.recordPositionsFrom(pc, this.sourceStart); + // subclass redefine printExpressionNoParenthesis() + output.append('('); + return printExpressionNoParenthesis(0, output).append(')'); + } + + public StringBuffer printExpressionNoParenthesis(int indent, + StringBuffer output) { + + lhs.printExpression(indent, output).append(" = "); //$NON-NLS-1$ + return expression.printExpression(0, output); + } + + public StringBuffer printStatement(int indent, StringBuffer output) { + + // no () when used as a statement + return print(indent, output).append(';'); } public TypeBinding resolveType(BlockScope scope) { - // due to syntax lhs may be only a NameReference, a FieldReference or an ArrayReference + // due to syntax lhs may be only a NameReference, a FieldReference or an + // ArrayReference constant = NotAConstant; - this.lhsType = lhs.resolveType(scope); - TypeBinding expressionTb = expression.resolveType(scope); - if (this.lhsType == null || expressionTb == null) + if (!(this.lhs instanceof Reference)) { + scope.problemReporter().expressionShouldBeAVariable(this.lhs); + } + this.resolvedType = lhs.resolveType(scope); // expressionType contains + // the assignment type (lhs + // Type) + TypeBinding rhsType = expression.resolveType(scope); + if (this.resolvedType == null || rhsType == null) { return null; + } + checkAssignmentEffect(scope); - // Compile-time conversion of base-types : implicit narrowing integer into byte/short/character + // Compile-time conversion of base-types : implicit narrowing integer + // into byte/short/character // may require to widen the rhs expression at runtime - if ((expression.isConstantValueOfTypeAssignableToType(expressionTb, this.lhsType) - || (this.lhsType.isBaseType() && BaseTypeBinding.isWidening(this.lhsType.id, expressionTb.id))) - || (scope.areTypesCompatible(expressionTb, this.lhsType))) { - expression.implicitWidening(this.lhsType, expressionTb); - return this.lhsType; + if ((expression.isConstantValueOfTypeAssignableToType(rhsType, + this.resolvedType) || (this.resolvedType.isBaseType() && BaseTypeBinding + .isWidening(this.resolvedType.id, rhsType.id))) + || rhsType.isCompatibleWith(this.resolvedType)) { + expression.implicitWidening(this.resolvedType, rhsType); + return this.resolvedType; } scope.problemReporter().typeMismatchErrorActualTypeExpectedType( - expression, - expressionTb, - this.lhsType); - return null; + expression, rhsType, this.resolvedType); + return this.resolvedType; } public String toString(int tab) { - //no () when used as a statement + // no () when used as a statement return tabString(tab) + toStringExpressionNoParenthesis(); } public String toStringExpression() { - //subclass redefine toStringExpressionNoParenthesis() + // subclass redefine toStringExpressionNoParenthesis() return "(" + toStringExpressionNoParenthesis() + ")"; //$NON-NLS-2$ //$NON-NLS-1$ - } - + } + public String toStringExpressionNoParenthesis() { - return lhs.toStringExpression() + " " //$NON-NLS-1$ - + "=" //$NON-NLS-1$ - + ((expression.constant != null) && (expression.constant != NotAConstant) - ? " /*cst:" + expression.constant.toString() + "*/ " //$NON-NLS-1$ //$NON-NLS-2$ - : " ") //$NON-NLS-1$ - + expression.toStringExpression(); + return lhs.toStringExpression() + + " " //$NON-NLS-1$ + + "=" //$NON-NLS-1$ + + ((expression.constant != null) + && (expression.constant != NotAConstant) ? " /*cst:" + expression.constant.toString() + "*/ " //$NON-NLS-1$ //$NON-NLS-2$ + : " ") //$NON-NLS-1$ + + expression.toStringExpression(); } - public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) { - + + public void traverse(ASTVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { lhs.traverse(visitor, scope); expression.traverse(visitor, scope);