KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > ast > Assignment


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  * Genady Beriozkin - added support for reporting assignment with no effect
11  *******************************************************************************/

12 package org.eclipse.jdt.internal.compiler.ast;
13
14 import org.eclipse.jdt.internal.compiler.ASTVisitor;
15 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
16 import org.eclipse.jdt.internal.compiler.codegen.*;
17 import org.eclipse.jdt.internal.compiler.flow.*;
18 import org.eclipse.jdt.internal.compiler.impl.Constant;
19 import org.eclipse.jdt.internal.compiler.lookup.*;
20
21 public class Assignment extends Expression {
22
23     public Expression lhs;
24     public Expression expression;
25         
26 public Assignment(Expression lhs, Expression expression, int sourceEnd) {
27     //lhs is always a reference by construction ,
28
//but is build as an expression ==> the checkcast cannot fail
29
this.lhs = lhs;
30     lhs.bits |= IsStrictlyAssigned; // tag lhs as assigned
31
this.expression = expression;
32     this.sourceStart = lhs.sourceStart;
33     this.sourceEnd = sourceEnd;
34 }
35
36 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
37     // record setting a variable: various scenarii are possible, setting an array reference,
38
// a field reference, a blank final field reference, a field of an enclosing instance or
39
// just a local variable.
40
LocalVariableBinding local = this.lhs.localVariableBinding();
41     int nullStatus = this.expression.nullStatus(flowInfo);
42     if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
43         if (nullStatus == FlowInfo.NULL) {
44             flowContext.recordUsingNullReference(currentScope, local, this.lhs,
45                 FlowContext.CAN_ONLY_NULL | FlowContext.IN_ASSIGNMENT, flowInfo);
46         }
47     }
48     flowInfo = ((Reference) lhs)
49         .analyseAssignment(currentScope, flowContext, flowInfo, this, false)
50         .unconditionalInits();
51     if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
52         switch(nullStatus) {
53             case FlowInfo.NULL :
54                 flowInfo.markAsDefinitelyNull(local);
55                 break;
56             case FlowInfo.NON_NULL :
57                 flowInfo.markAsDefinitelyNonNull(local);
58                 break;
59             default:
60                 flowInfo.markAsDefinitelyUnknown(local);
61         }
62         if (flowContext.initsOnFinally != null) {
63             switch(nullStatus) {
64                 case FlowInfo.NULL :
65                     flowContext.initsOnFinally.markAsDefinitelyNull(local);
66                     break;
67                 case FlowInfo.NON_NULL :
68                     flowContext.initsOnFinally.markAsDefinitelyNonNull(local);
69                     break;
70                 default:
71                     flowContext.initsOnFinally.markAsDefinitelyUnknown(local);
72             }
73         }
74     }
75     return flowInfo;
76 }
77
78 void checkAssignment(BlockScope scope, TypeBinding lhsType, TypeBinding rhsType) {
79     FieldBinding leftField = getLastField(this.lhs);
80     if (leftField != null && rhsType != TypeBinding.NULL && lhsType.isWildcard() && ((WildcardBinding)lhsType).boundKind != Wildcard.SUPER) {
81         scope.problemReporter().wildcardAssignment(lhsType, rhsType, this.expression);
82     } else if (leftField != null && !leftField.isStatic() && leftField.declaringClass != null /*length pseudo field*/&& leftField.declaringClass.isRawType()) {
83         scope.problemReporter().unsafeRawFieldAssignment(leftField, rhsType, this.lhs);
84     } else if (rhsType.needsUncheckedConversion(lhsType)) {
85         scope.problemReporter().unsafeTypeConversion(this.expression, rhsType, lhsType);
86     }
87 }
88
89 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
90     // various scenarii are possible, setting an array reference,
91
// a field reference, a blank final field reference, a field of an enclosing instance or
92
// just a local variable.
93

94     int pc = codeStream.position;
95      ((Reference) lhs).generateAssignment(currentScope, codeStream, this, valueRequired);
96     // variable may have been optimized out
97
// the lhs is responsible to perform the implicitConversion generation for the assignment since optimized for unused local assignment.
98
codeStream.recordPositionsFrom(pc, this.sourceStart);
99 }
100
101 public static Binding getDirectBinding(Expression someExpression) {
102     if ((someExpression.bits & ASTNode.IgnoreNoEffectAssignCheck) != 0) {
103         return null;
104     }
105     if (someExpression instanceof SingleNameReference) {
106         return ((SingleNameReference)someExpression).binding;
107     } else if (someExpression instanceof FieldReference) {
108         FieldReference fieldRef = (FieldReference)someExpression;
109         if (fieldRef.receiver.isThis() && !(fieldRef.receiver instanceof QualifiedThisReference)) {
110             return fieldRef.binding;
111         }
112     } else if (someExpression instanceof Assignment) {
113         Expression lhs = ((Assignment)someExpression).lhs;
114         if ((lhs.bits & ASTNode.IsStrictlyAssigned) != 0) {
115             // i = i = ...; // eq to int i = ...;
116
return getDirectBinding (((Assignment)someExpression).lhs);
117         } else if (someExpression instanceof PrefixExpression) {
118             // i = i++; // eq to ++i;
119
return getDirectBinding (((Assignment)someExpression).lhs);
120         }
121     }
122 // } else if (someExpression instanceof PostfixExpression) { // recurse for postfix: i++ --> i
123
// // note: "b = b++" is equivalent to doing nothing, not to "b++"
124
// return getDirectBinding(((PostfixExpression) someExpression).lhs);
125
return null;
126 }
127
128 FieldBinding getLastField(Expression someExpression) {
129     if (someExpression instanceof SingleNameReference) {
130         if ((someExpression.bits & RestrictiveFlagMASK) == Binding.FIELD) {
131             return (FieldBinding) ((SingleNameReference)someExpression).binding;
132         }
133     } else if (someExpression instanceof FieldReference) {
134         return ((FieldReference)someExpression).binding;
135     } else if (someExpression instanceof QualifiedNameReference) {
136         QualifiedNameReference qName = (QualifiedNameReference) someExpression;
137         if (qName.otherBindings == null) {
138             if ((someExpression.bits & RestrictiveFlagMASK) == Binding.FIELD) {
139                 return (FieldBinding)qName.binding;
140             }
141         } else {
142             return qName.otherBindings[qName.otherBindings.length - 1];
143         }
144     }
145     return null;
146 }
147
148 public int nullStatus(FlowInfo flowInfo) {
149     return this.expression.nullStatus(flowInfo);
150 }
151
152 public StringBuffer JavaDoc print(int indent, StringBuffer JavaDoc output) {
153     //no () when used as a statement
154
printIndent(indent, output);
155     return printExpressionNoParenthesis(indent, output);
156 }
157 public StringBuffer JavaDoc printExpression(int indent, StringBuffer JavaDoc output) {
158     //subclass redefine printExpressionNoParenthesis()
159
output.append('(');
160     return printExpressionNoParenthesis(0, output).append(')');
161 }
162
163 public StringBuffer JavaDoc printExpressionNoParenthesis(int indent, StringBuffer JavaDoc output) {
164     lhs.printExpression(indent, output).append(" = "); //$NON-NLS-1$
165
return expression.printExpression(0, output);
166 }
167
168 public StringBuffer JavaDoc printStatement(int indent, StringBuffer JavaDoc output) {
169     //no () when used as a statement
170
return print(indent, output).append(';');
171 }
172
173 public TypeBinding resolveType(BlockScope scope) {
174     // due to syntax lhs may be only a NameReference, a FieldReference or an ArrayReference
175
this.constant = Constant.NotAConstant;
176     if (!(this.lhs instanceof Reference) || this.lhs.isThis()) {
177         scope.problemReporter().expressionShouldBeAVariable(this.lhs);
178         return null;
179     }
180     TypeBinding lhsType = lhs.resolveType(scope);
181     this.expression.setExpectedType(lhsType); // needed in case of generic method invocation
182
if (lhsType != null)
183         this.resolvedType = lhsType.capture(scope, this.sourceEnd);
184     TypeBinding rhsType = this.expression.resolveType(scope);
185     if (lhsType == null || rhsType == null) {
186         return null;
187     }
188     
189     // check for assignment with no effect
190
Binding left = getDirectBinding(this.lhs);
191     if (left != null && left == getDirectBinding(this.expression)) {
192         scope.problemReporter().assignmentHasNoEffect(this, left.shortReadableName());
193     }
194
195     // Compile-time conversion of base-types : implicit narrowing integer into byte/short/character
196
// may require to widen the rhs expression at runtime
197
if (lhsType != rhsType) // must call before computeConversion() and typeMismatchError()
198
scope.compilationUnitScope().recordTypeConversion(lhsType, rhsType);
199     if ((this.expression.isConstantValueOfTypeAssignableToType(rhsType, lhsType)
200             || (lhsType.isBaseType() && BaseTypeBinding.isWidening(lhsType.id, rhsType.id)))
201             || rhsType.isCompatibleWith(lhsType)) {
202         this.expression.computeConversion(scope, lhsType, rhsType);
203         checkAssignment(scope, lhsType, rhsType);
204         if (this.expression instanceof CastExpression
205                 && (this.expression.bits & ASTNode.UnnecessaryCast) == 0) {
206             CastExpression.checkNeedForAssignedCast(scope, lhsType, (CastExpression) this.expression);
207         }
208         return this.resolvedType;
209     } else if (scope.isBoxingCompatibleWith(rhsType, lhsType)
210                         || (rhsType.isBaseType() // narrowing then boxing ?
211
&& scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 // autoboxing
212
&& !lhsType.isBaseType()
213                                 && this.expression.isConstantValueOfTypeAssignableToType(rhsType, scope.environment().computeBoxingType(lhsType)))) {
214         this.expression.computeConversion(scope, lhsType, rhsType);
215         if (this.expression instanceof CastExpression
216                 && (this.expression.bits & ASTNode.UnnecessaryCast) == 0) {
217             CastExpression.checkNeedForAssignedCast(scope, lhsType, (CastExpression) this.expression);
218         }
219         return this.resolvedType;
220     }
221     scope.problemReporter().typeMismatchError(rhsType, lhsType, this.expression);
222     return lhsType;
223 }
224
225 /**
226  * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveTypeExpecting(org.eclipse.jdt.internal.compiler.lookup.BlockScope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding)
227  */

228 public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedType) {
229
230     TypeBinding type = super.resolveTypeExpecting(scope, expectedType);
231     if (type == null) return null;
232     TypeBinding lhsType = this.resolvedType;
233     TypeBinding rhsType = this.expression.resolvedType;
234     // signal possible accidental boolean assignment (instead of using '==' operator)
235
if (expectedType == TypeBinding.BOOLEAN
236             && lhsType == TypeBinding.BOOLEAN
237             && (this.lhs.bits & IsStrictlyAssigned) != 0) {
238         scope.problemReporter().possibleAccidentalBooleanAssignment(this);
239     }
240     checkAssignment(scope, lhsType, rhsType);
241     return type;
242 }
243
244 public void traverse(ASTVisitor visitor, BlockScope scope) {
245     if (visitor.visit(this, scope)) {
246         lhs.traverse(visitor, scope);
247         expression.traverse(visitor, scope);
248     }
249     visitor.endVisit(this, scope);
250 }
251 public LocalVariableBinding localVariableBinding() {
252     return lhs.localVariableBinding();
253 }
254 }
255
Popular Tags