X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2Fast%2FAssignment.java;fp=src%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2Fast%2FAssignment.java;h=5b86adec80b222f735daca7aa31331caaa8f8ad0;hb=040fa5af2cd00017cf3575950cdaade34a6d7f6c;hp=0000000000000000000000000000000000000000;hpb=a580fb8376d315d05e4d6bfdff9ff1101a151cd6;p=org.ibex.tool.git diff --git a/src/org/eclipse/jdt/internal/compiler/ast/Assignment.java b/src/org/eclipse/jdt/internal/compiler/ast/Assignment.java new file mode 100644 index 0000000..5b86ade --- /dev/null +++ b/src/org/eclipse/jdt/internal/compiler/ast/Assignment.java @@ -0,0 +1,172 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * 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-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Genady Beriozkin - added support for reporting assignment with no effect + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +public class Assignment extends Expression { + + public Expression lhs; + public Expression expression; + + 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 + + this.lhs = lhs; + lhs.bits |= IsStrictlyAssignedMASK; // tag lhs as assigned + + 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 + // just a local variable. + + return ((Reference) lhs) + .analyseAssignment(currentScope, flowContext, flowInfo, this, false) + .unconditionalInits(); + } + + void checkAssignmentEffect(BlockScope scope) { + + 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) { + + //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 + constant = NotAConstant; + if (!(this.lhs instanceof Reference) || this.lhs.isThis()) { + scope.problemReporter().expressionShouldBeAVariable(this.lhs); + return null; + } + 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 + // may require to widen the rhs expression at runtime + 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, + rhsType, + this.resolvedType); + return this.resolvedType; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveTypeExpecting(org.eclipse.jdt.internal.compiler.lookup.BlockScope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding) + */ + public TypeBinding resolveTypeExpecting( + BlockScope scope, + TypeBinding expectedType) { + + TypeBinding type = super.resolveTypeExpecting(scope, expectedType); + // signal possible accidental boolean assignment (instead of using '==' operator) + if (expectedType == BooleanBinding + && this.lhs.resolvedType == BooleanBinding + && (this.lhs.bits & IsStrictlyAssignedMASK) != 0) { + scope.problemReporter().possibleAccidentalBooleanAssignment(this); + } + + return type; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + lhs.traverse(visitor, scope); + expression.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +} \ No newline at end of file