1 /*******************************************************************************
2 * Copyright (c) 2000, 2013 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 * Stephan Herrmann - Contribution for
11 * bug 383368 - [compiler][null] syntactic null analysis for field references
12 * bug 403086 - [compiler][null] include the effect of 'assert' in syntactic null analysis for fields
13 *******************************************************************************/
14 package org.eclipse.jdt.internal.compiler.ast;
15
16 import org.eclipse.jdt.internal.compiler.ASTVisitor;
17 import org.eclipse.jdt.internal.compiler.impl.*;
18 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
19 import org.eclipse.jdt.internal.compiler.codegen.*;
20 import org.eclipse.jdt.internal.compiler.flow.*;
21 import org.eclipse.jdt.internal.compiler.lookup.*;
22
23 public class UnaryExpression extends OperatorExpression {
24
25 public Expression expression;
26 public Constant optimizedBooleanConstant;
27
UnaryExpression(Expression expression, int operator)28 public UnaryExpression(Expression expression, int operator) {
29 this.expression = expression;
30 this.bits |= operator << OperatorSHIFT; // encode operator
31 }
32
analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo)33 public FlowInfo analyseCode(
34 BlockScope currentScope,
35 FlowContext flowContext,
36 FlowInfo flowInfo) {
37 this.expression.checkNPE(currentScope, flowContext, flowInfo);
38 if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
39 flowContext.tagBits ^= FlowContext.INSIDE_NEGATION;
40 flowInfo = this.expression.
41 analyseCode(currentScope, flowContext, flowInfo).
42 asNegatedCondition();
43 flowContext.tagBits ^= FlowContext.INSIDE_NEGATION;
44 return flowInfo;
45 } else {
46 return this.expression.
47 analyseCode(currentScope, flowContext, flowInfo);
48 }
49 }
50
optimizedBooleanConstant()51 public Constant optimizedBooleanConstant() {
52
53 return this.optimizedBooleanConstant == null
54 ? this.constant
55 : this.optimizedBooleanConstant;
56 }
57
58 /**
59 * Code generation for an unary operation
60 *
61 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
62 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
63 * @param valueRequired boolean
64 */
generateCode( BlockScope currentScope, CodeStream codeStream, boolean valueRequired)65 public void generateCode(
66 BlockScope currentScope,
67 CodeStream codeStream,
68 boolean valueRequired) {
69
70 int pc = codeStream.position;
71 BranchLabel falseLabel, endifLabel;
72 if (this.constant != Constant.NotAConstant) {
73 // inlined value
74 if (valueRequired) {
75 codeStream.generateConstant(this.constant, this.implicitConversion);
76 }
77 codeStream.recordPositionsFrom(pc, this.sourceStart);
78 return;
79 }
80 switch ((this.bits & OperatorMASK) >> OperatorSHIFT) {
81 case NOT :
82 switch ((this.expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) /* runtime type */ {
83 case T_boolean :
84 // ! <boolean>
85 // Generate code for the condition
86 this.expression.generateOptimizedBoolean(
87 currentScope,
88 codeStream,
89 null,
90 (falseLabel = new BranchLabel(codeStream)),
91 valueRequired);
92 if (valueRequired) {
93 codeStream.iconst_0();
94 if (falseLabel.forwardReferenceCount() > 0) {
95 codeStream.goto_(endifLabel = new BranchLabel(codeStream));
96 codeStream.decrStackSize(1);
97 falseLabel.place();
98 codeStream.iconst_1();
99 endifLabel.place();
100 }
101 } else { // 6596: if (!(a && b)){} - must still place falseLabel
102 falseLabel.place();
103 }
104 break;
105 }
106 break;
107 case TWIDDLE :
108 switch ((this.expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4 /* runtime */) {
109 case T_int :
110 // ~int
111 this.expression.generateCode(currentScope, codeStream, valueRequired);
112 if (valueRequired) {
113 codeStream.iconst_m1();
114 codeStream.ixor();
115 }
116 break;
117 case T_long :
118 this.expression.generateCode(currentScope, codeStream, valueRequired);
119 if (valueRequired) {
120 codeStream.ldc2_w(-1L);
121 codeStream.lxor();
122 }
123 }
124 break;
125 case MINUS :
126 // - <num>
127 if (this.constant != Constant.NotAConstant) {
128 if (valueRequired) {
129 switch ((this.expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4){ /* runtime */
130 case T_int :
131 codeStream.generateInlinedValue(this.constant.intValue() * -1);
132 break;
133 case T_float :
134 codeStream.generateInlinedValue(this.constant.floatValue() * -1.0f);
135 break;
136 case T_long :
137 codeStream.generateInlinedValue(this.constant.longValue() * -1L);
138 break;
139 case T_double :
140 codeStream.generateInlinedValue(this.constant.doubleValue() * -1.0);
141 }
142 }
143 } else {
144 this.expression.generateCode(currentScope, codeStream, valueRequired);
145 if (valueRequired) {
146 switch ((this.expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4){ /* runtime type */
147 case T_int :
148 codeStream.ineg();
149 break;
150 case T_float :
151 codeStream.fneg();
152 break;
153 case T_long :
154 codeStream.lneg();
155 break;
156 case T_double :
157 codeStream.dneg();
158 }
159 }
160 }
161 break;
162 case PLUS :
163 this.expression.generateCode(currentScope, codeStream, valueRequired);
164 }
165 if (valueRequired) {
166 codeStream.generateImplicitConversion(this.implicitConversion);
167 }
168 codeStream.recordPositionsFrom(pc, this.sourceStart);
169 }
170
171 /**
172 * Boolean operator code generation
173 * Optimized operations are: &&, ||, <, <=, >, >=, &, |, ^
174 */
generateOptimizedBoolean( BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired)175 public void generateOptimizedBoolean(
176 BlockScope currentScope,
177 CodeStream codeStream,
178 BranchLabel trueLabel,
179 BranchLabel falseLabel,
180 boolean valueRequired) {
181
182 if ((this.constant != Constant.NotAConstant) && (this.constant.typeID() == T_boolean)) {
183 super.generateOptimizedBoolean(
184 currentScope,
185 codeStream,
186 trueLabel,
187 falseLabel,
188 valueRequired);
189 return;
190 }
191 if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
192 this.expression.generateOptimizedBoolean(
193 currentScope,
194 codeStream,
195 falseLabel,
196 trueLabel,
197 valueRequired);
198 } else {
199 super.generateOptimizedBoolean(
200 currentScope,
201 codeStream,
202 trueLabel,
203 falseLabel,
204 valueRequired);
205 }
206 }
207
printExpressionNoParenthesis(int indent, StringBuffer output)208 public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
209
210 output.append(operatorToString()).append(' ');
211 return this.expression.printExpression(0, output);
212 }
213
resolveType(BlockScope scope)214 public TypeBinding resolveType(BlockScope scope) {
215 boolean expressionIsCast;
216 if ((expressionIsCast = this.expression instanceof CastExpression) == true) this.expression.bits |= DisableUnnecessaryCastCheck; // will check later on
217 TypeBinding expressionType = this.expression.resolveType(scope);
218 if (expressionType == null) {
219 this.constant = Constant.NotAConstant;
220 return null;
221 }
222 int expressionTypeID = expressionType.id;
223 // autoboxing support
224 boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
225 if (use15specifics) {
226 if (!expressionType.isBaseType()) {
227 expressionTypeID = scope.environment().computeBoxingType(expressionType).id;
228 }
229 }
230 if (expressionTypeID > 15) {
231 this.constant = Constant.NotAConstant;
232 scope.problemReporter().invalidOperator(this, expressionType);
233 return null;
234 }
235
236 int tableId;
237 switch ((this.bits & OperatorMASK) >> OperatorSHIFT) {
238 case NOT :
239 tableId = AND_AND;
240 break;
241 case TWIDDLE :
242 tableId = LEFT_SHIFT;
243 break;
244 default :
245 tableId = MINUS;
246 } //+ and - cases
247
248 // the code is an int
249 // (cast) left Op (cast) rigth --> result
250 // 0000 0000 0000 0000 0000
251 // <<16 <<12 <<8 <<4 <<0
252 int operatorSignature = OperatorSignatures[tableId][(expressionTypeID << 4) + expressionTypeID];
253 this.expression.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), expressionType);
254 this.bits |= operatorSignature & 0xF;
255 switch (operatorSignature & 0xF) { // only switch on possible result type.....
256 case T_boolean :
257 this.resolvedType = TypeBinding.BOOLEAN;
258 break;
259 case T_byte :
260 this.resolvedType = TypeBinding.BYTE;
261 break;
262 case T_char :
263 this.resolvedType = TypeBinding.CHAR;
264 break;
265 case T_double :
266 this.resolvedType = TypeBinding.DOUBLE;
267 break;
268 case T_float :
269 this.resolvedType = TypeBinding.FLOAT;
270 break;
271 case T_int :
272 this.resolvedType = TypeBinding.INT;
273 break;
274 case T_long :
275 this.resolvedType = TypeBinding.LONG;
276 break;
277 default : //error........
278 this.constant = Constant.NotAConstant;
279 if (expressionTypeID != T_undefined)
280 scope.problemReporter().invalidOperator(this, expressionType);
281 return null;
282 }
283 // compute the constant when valid
284 if (this.expression.constant != Constant.NotAConstant) {
285 this.constant =
286 Constant.computeConstantOperation(
287 this.expression.constant,
288 expressionTypeID,
289 (this.bits & OperatorMASK) >> OperatorSHIFT);
290 } else {
291 this.constant = Constant.NotAConstant;
292 if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
293 Constant cst = this.expression.optimizedBooleanConstant();
294 if (cst != Constant.NotAConstant)
295 this.optimizedBooleanConstant = BooleanConstant.fromValue(!cst.booleanValue());
296 }
297 }
298 if (expressionIsCast) {
299 // check need for operand cast
300 CastExpression.checkNeedForArgumentCast(scope, tableId, operatorSignature, this.expression, expressionTypeID);
301 }
302 return this.resolvedType;
303 }
304
traverse( ASTVisitor visitor, BlockScope blockScope)305 public void traverse(
306 ASTVisitor visitor,
307 BlockScope blockScope) {
308
309 if (visitor.visit(this, blockScope)) {
310 this.expression.traverse(visitor, blockScope);
311 }
312 visitor.endVisit(this, blockScope);
313 }
314 }
315