removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / Assignment.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-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.codegen.*;
16 import org.eclipse.jdt.internal.compiler.flow.*;
17 import org.eclipse.jdt.internal.compiler.lookup.*;
18
19 public class Assignment extends Expression {
20
21         public Expression lhs;
22         public Expression expression;
23                 
24         public Assignment(Expression lhs, Expression expression, int sourceEnd) {
25                 //lhs is always a reference by construction ,
26                 //but is build as an expression ==> the checkcast cannot fail
27
28                 this.lhs = lhs;
29                 lhs.bits |= IsStrictlyAssignedMASK; // tag lhs as assigned
30                 
31                 this.expression = expression;
32
33                 this.sourceStart = lhs.sourceStart;
34                 this.sourceEnd = sourceEnd;
35         }
36
37         public FlowInfo analyseCode(
38                 BlockScope currentScope,
39                 FlowContext flowContext,
40                 FlowInfo flowInfo) {
41                 // record setting a variable: various scenarii are possible, setting an array reference, 
42                 // a field reference, a blank final field reference, a field of an enclosing instance or 
43                 // just a local variable.
44
45                 return ((Reference) lhs)
46                         .analyseAssignment(currentScope, flowContext, flowInfo, this, false)
47                         .unconditionalInits();
48         }
49
50         void checkAssignmentEffect(BlockScope scope) {
51                 
52                 Binding left = getDirectBinding(this.lhs);
53                 if (left != null && left == getDirectBinding(this.expression)) {
54                         scope.problemReporter().assignmentHasNoEffect(this, left.shortReadableName());
55                         this.bits |= IsAssignmentWithNoEffectMASK; // record assignment has no effect
56                 }
57         }
58
59         public void generateCode(
60                 BlockScope currentScope,
61                 CodeStream codeStream,
62                 boolean valueRequired) {
63
64                 // various scenarii are possible, setting an array reference, 
65                 // a field reference, a blank final field reference, a field of an enclosing instance or 
66                 // just a local variable.
67
68                 int pc = codeStream.position;
69                 if ((this.bits & IsAssignmentWithNoEffectMASK) != 0) {
70                         if (valueRequired) {
71                                 this.expression.generateCode(currentScope, codeStream, true);
72                         }
73                 } else {
74                          ((Reference) lhs).generateAssignment(currentScope, codeStream, this, valueRequired);
75                         // variable may have been optimized out
76                         // the lhs is responsible to perform the implicitConversion generation for the assignment since optimized for unused local assignment.
77                 }
78                 codeStream.recordPositionsFrom(pc, this.sourceStart);
79         }
80
81         Binding getDirectBinding(Expression someExpression) {
82                 if (someExpression instanceof SingleNameReference) {
83                         return ((SingleNameReference)someExpression).binding;
84                 } else if (someExpression instanceof FieldReference) {
85                         FieldReference fieldRef = (FieldReference)someExpression;
86                         if (fieldRef.receiver.isThis() && !(fieldRef.receiver instanceof QualifiedThisReference)) {
87                                 return fieldRef.binding;
88                         }                       
89                 }
90                 return null;
91         }
92         public StringBuffer print(int indent, StringBuffer output) {
93
94                 //no () when used as a statement 
95                 printIndent(indent, output);
96                 return printExpressionNoParenthesis(indent, output);
97         }
98         public StringBuffer printExpression(int indent, StringBuffer output) {
99
100                 //subclass redefine printExpressionNoParenthesis()
101                 output.append('(');
102                 return printExpressionNoParenthesis(0, output).append(')');
103         } 
104
105         public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
106
107                 lhs.printExpression(indent, output).append(" = "); //$NON-NLS-1$
108                 return expression.printExpression(0, output);
109         }
110         
111         public StringBuffer printStatement(int indent, StringBuffer output) {
112
113                 //no () when used as a statement 
114                 return print(indent, output).append(';');
115         }
116
117         public TypeBinding resolveType(BlockScope scope) {
118
119                 // due to syntax lhs may be only a NameReference, a FieldReference or an ArrayReference
120                 constant = NotAConstant;
121                 if (!(this.lhs instanceof Reference) || this.lhs.isThis()) {
122                         scope.problemReporter().expressionShouldBeAVariable(this.lhs);
123                         return null;
124                 }
125                 this.resolvedType = lhs.resolveType(scope); // expressionType contains the assignment type (lhs Type)
126                 TypeBinding rhsType = expression.resolveType(scope);
127                 if (this.resolvedType == null || rhsType == null) {
128                         return null;
129                 }
130                 checkAssignmentEffect(scope);
131                                 
132                 // Compile-time conversion of base-types : implicit narrowing integer into byte/short/character
133                 // may require to widen the rhs expression at runtime
134                 if ((expression.isConstantValueOfTypeAssignableToType(rhsType, this.resolvedType)
135                                 || (this.resolvedType.isBaseType() && BaseTypeBinding.isWidening(this.resolvedType.id, rhsType.id)))
136                                 || rhsType.isCompatibleWith(this.resolvedType)) {
137                         expression.implicitWidening(this.resolvedType, rhsType);
138                         return this.resolvedType;
139                 }
140                 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
141                         expression,
142                         rhsType,
143                         this.resolvedType);
144                 return this.resolvedType;
145         }
146         /* (non-Javadoc)
147          * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveTypeExpecting(org.eclipse.jdt.internal.compiler.lookup.BlockScope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding)
148          */
149         public TypeBinding resolveTypeExpecting(
150                         BlockScope scope,
151                         TypeBinding expectedType) {
152
153                 TypeBinding type = super.resolveTypeExpecting(scope, expectedType);
154                 // signal possible accidental boolean assignment (instead of using '==' operator)
155                 if (expectedType == BooleanBinding 
156                                 && this.lhs.resolvedType == BooleanBinding 
157                                 && (this.lhs.bits & IsStrictlyAssignedMASK) != 0) {
158                         scope.problemReporter().possibleAccidentalBooleanAssignment(this);
159                 }
160
161                 return type;
162         }
163
164         public void traverse(ASTVisitor visitor, BlockScope scope) {
165                 
166                 if (visitor.visit(this, scope)) {
167                         lhs.traverse(visitor, scope);
168                         expression.traverse(visitor, scope);
169                 }
170                 visitor.endVisit(this, scope);
171         }
172 }