1 package com
.intellij
.psi
.impl
;
3 import com
.intellij
.openapi
.project
.Project
;
4 import com
.intellij
.openapi
.util
.Key
;
5 import com
.intellij
.psi
.*;
6 import com
.intellij
.psi
.tree
.IElementType
;
7 import com
.intellij
.psi
.util
.*;
8 import com
.intellij
.util
.ConcurrencyUtil
;
9 import com
.intellij
.util
.containers
.ConcurrentSoftHashMap
;
10 import com
.intellij
.util
.containers
.StringInterner
;
11 import gnu
.trove
.THashSet
;
12 import org
.jetbrains
.annotations
.NotNull
;
15 import java
.util
.concurrent
.ConcurrentMap
;
17 public class ConstantExpressionEvaluator
extends JavaElementVisitor
{
18 private final StringInterner myInterner
= new StringInterner();
20 private Set
<PsiVariable
> myVisitedVars
;
21 private final boolean myThrowExceptionOnOverflow
;
22 private final Project myProject
;
24 private Object myValue
;
26 private static final Key
<CachedValue
<ConcurrentMap
<PsiElement
,Object
>>> CONSTANT_VALUE_WO_OVERFLOW_MAP_KEY
= Key
.create("CONSTANT_VALUE_WO_OVERFLOW_MAP_KEY");
27 private static final Key
<CachedValue
<ConcurrentMap
<PsiElement
,Object
>>> CONSTANT_VALUE_WITH_OVERFLOW_MAP_KEY
= Key
.create("CONSTANT_VALUE_WITH_OVERFLOW_MAP_KEY");
28 private static final Object NO_VALUE
= new Object();
30 private ConstantExpressionEvaluator(Set
<PsiVariable
> visitedVars
, boolean throwExceptionOnOverflow
, final Project project
) {
31 myVisitedVars
= visitedVars
;
32 myThrowExceptionOnOverflow
= throwExceptionOnOverflow
;
36 @Override public void visitLiteralExpression(PsiLiteralExpression expression
) {
37 final Object value
= expression
.getValue();
38 myValue
= value
instanceof String? myInterner
.intern((String
)value
) : value
;
41 @Override public void visitBinaryExpression(PsiBinaryExpression expression
) {
42 Object lOperandValue
= accept(expression
.getLOperand());
43 if (lOperandValue
== null) {
48 Object rOperandValue
= accept(expression
.getROperand());
49 if (rOperandValue
== null) {
54 PsiJavaToken operationSign
= expression
.getOperationSign();
55 final IElementType tokenType
= operationSign
.getTokenType();
58 if (tokenType
== JavaTokenType
.LT
) {
59 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
60 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
61 if (lOperandValue
instanceof Number
&& rOperandValue
instanceof Number
) {
62 value
= Boolean
.valueOf(((Number
)lOperandValue
).doubleValue() < ((Number
)rOperandValue
).doubleValue());
65 else if (tokenType
== JavaTokenType
.LE
) {
66 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
67 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
68 if (lOperandValue
instanceof Number
&& rOperandValue
instanceof Number
) {
69 value
= Boolean
.valueOf(((Number
)lOperandValue
).doubleValue() <= ((Number
)rOperandValue
).doubleValue());
72 else if (tokenType
== JavaTokenType
.GT
) {
73 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
74 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
75 if (lOperandValue
instanceof Number
&& rOperandValue
instanceof Number
) {
76 value
= Boolean
.valueOf(((Number
)lOperandValue
).doubleValue() > ((Number
)rOperandValue
).doubleValue());
79 else if (tokenType
== JavaTokenType
.GE
) {
80 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
81 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
82 if (lOperandValue
instanceof Number
&& rOperandValue
instanceof Number
) {
83 value
= Boolean
.valueOf(((Number
)lOperandValue
).doubleValue() >= ((Number
)rOperandValue
).doubleValue());
86 else if (tokenType
== JavaTokenType
.EQEQ
) {
87 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
88 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
89 if (lOperandValue
instanceof Number
&& rOperandValue
instanceof Number
) {
90 value
= Boolean
.valueOf(((Number
)lOperandValue
).doubleValue() == ((Number
)rOperandValue
).doubleValue());
92 else if (lOperandValue
instanceof String
&& rOperandValue
instanceof String
) {
93 value
= Boolean
.valueOf(lOperandValue
== rOperandValue
);
95 else if (lOperandValue
instanceof Boolean
&& rOperandValue
instanceof Boolean
) {
96 value
= Boolean
.valueOf(((Boolean
)lOperandValue
).booleanValue() == ((Boolean
)rOperandValue
).booleanValue());
99 else if (tokenType
== JavaTokenType
.NE
) {
100 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
101 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
102 if (lOperandValue
instanceof Number
&& rOperandValue
instanceof Number
) {
103 value
= Boolean
.valueOf(((Number
)lOperandValue
).doubleValue() != ((Number
)rOperandValue
).doubleValue());
105 else if (lOperandValue
instanceof String
&& rOperandValue
instanceof String
) {
106 value
= Boolean
.valueOf(lOperandValue
!= rOperandValue
);
108 else if (lOperandValue
instanceof Boolean
&& rOperandValue
instanceof Boolean
) {
109 value
= Boolean
.valueOf(((Boolean
)lOperandValue
).booleanValue() != ((Boolean
)rOperandValue
).booleanValue());
112 else if (tokenType
== JavaTokenType
.PLUS
) {
113 if (lOperandValue
instanceof String
|| rOperandValue
instanceof String
) {
114 value
= myInterner
.intern(lOperandValue
.toString() + rOperandValue
.toString());
117 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
118 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
120 if (lOperandValue
instanceof Number
&& rOperandValue
instanceof Number
) {
121 if (lOperandValue
instanceof Double
|| rOperandValue
instanceof Double
) {
122 value
= new Double(((Number
)lOperandValue
).doubleValue() + ((Number
)rOperandValue
).doubleValue());
123 checkRealNumberOverflow(value
, lOperandValue
, rOperandValue
,expression
);
125 else if (lOperandValue
instanceof Float
|| rOperandValue
instanceof Float
) {
126 value
= new Float(((Number
)lOperandValue
).floatValue() + ((Number
)rOperandValue
).floatValue());
127 checkRealNumberOverflow(value
, lOperandValue
, rOperandValue
, expression
);
129 else if (lOperandValue
instanceof Long
|| rOperandValue
instanceof Long
) {
130 final long l
= ((Number
)lOperandValue
).longValue();
131 final long r
= ((Number
)rOperandValue
).longValue();
132 value
= Long
.valueOf(l
+ r
);
133 checkAdditionOverflow(((Long
)value
).longValue() >= 0, l
>= 0, r
>= 0, expression
);
136 final int l
= ((Number
)lOperandValue
).intValue();
137 final int r
= ((Number
)rOperandValue
).intValue();
138 value
= Integer
.valueOf(l
+ r
);
139 checkAdditionOverflow(((Integer
)value
).intValue() >= 0, l
>= 0, r
>= 0, expression
);
144 else if (tokenType
== JavaTokenType
.MINUS
) {
145 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
146 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
147 if (lOperandValue
instanceof Number
&& rOperandValue
instanceof Number
) {
148 if (lOperandValue
instanceof Double
|| rOperandValue
instanceof Double
) {
149 value
= new Double(((Number
)lOperandValue
).doubleValue() - ((Number
)rOperandValue
).doubleValue());
150 checkRealNumberOverflow(value
, lOperandValue
, rOperandValue
, expression
);
152 else if (lOperandValue
instanceof Float
|| rOperandValue
instanceof Float
) {
153 value
= new Float(((Number
)lOperandValue
).floatValue() - ((Number
)rOperandValue
).floatValue());
154 checkRealNumberOverflow(value
, lOperandValue
, rOperandValue
, expression
);
156 else if (lOperandValue
instanceof Long
|| rOperandValue
instanceof Long
) {
157 final long l
= ((Number
)lOperandValue
).longValue();
158 final long r
= ((Number
)rOperandValue
).longValue();
159 value
= Long
.valueOf(l
- r
);
160 checkAdditionOverflow(((Long
)value
).longValue() >= 0, l
>= 0, r
< 0, expression
);
163 final int l
= ((Number
)lOperandValue
).intValue();
164 final int r
= ((Number
)rOperandValue
).intValue();
165 value
= Integer
.valueOf(l
- r
);
166 checkAdditionOverflow(((Integer
)value
).intValue() >= 0, l
>= 0, r
< 0, expression
);
170 else if (tokenType
== JavaTokenType
.ASTERISK
) {
171 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
172 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
173 if (lOperandValue
instanceof Number
&& rOperandValue
instanceof Number
) {
174 if (lOperandValue
instanceof Double
|| rOperandValue
instanceof Double
) {
175 value
= new Double(((Number
)lOperandValue
).doubleValue() * ((Number
)rOperandValue
).doubleValue());
176 checkRealNumberOverflow(value
, lOperandValue
, rOperandValue
, expression
);
178 else if (lOperandValue
instanceof Float
|| rOperandValue
instanceof Float
) {
179 value
= new Float(((Number
)lOperandValue
).floatValue() * ((Number
)rOperandValue
).floatValue());
180 checkRealNumberOverflow(value
, lOperandValue
, rOperandValue
, expression
);
182 else if (lOperandValue
instanceof Long
|| rOperandValue
instanceof Long
) {
183 final long l
= ((Number
)lOperandValue
).longValue();
184 final long r
= ((Number
)rOperandValue
).longValue();
185 value
= Long
.valueOf(l
* r
);
186 checkMultiplicationOverflow(((Long
)value
).longValue(), l
, r
, expression
);
189 final int l
= ((Number
)lOperandValue
).intValue();
190 final int r
= ((Number
)rOperandValue
).intValue();
191 value
= Integer
.valueOf(l
* r
);
192 checkMultiplicationOverflow(((Integer
)value
).intValue(), l
, r
, expression
);
196 else if (tokenType
== JavaTokenType
.DIV
) {
197 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
198 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
199 if (lOperandValue
instanceof Number
&& rOperandValue
instanceof Number
) {
200 if (lOperandValue
instanceof Double
|| rOperandValue
instanceof Double
) {
201 value
= new Double(((Number
)lOperandValue
).doubleValue() / ((Number
)rOperandValue
).doubleValue());
202 checkRealNumberOverflow(value
, lOperandValue
, rOperandValue
, expression
);
204 else if (lOperandValue
instanceof Float
|| rOperandValue
instanceof Float
) {
205 value
= new Float(((Number
)lOperandValue
).floatValue() / ((Number
)rOperandValue
).floatValue());
206 checkRealNumberOverflow(value
, lOperandValue
, rOperandValue
, expression
);
208 else if (lOperandValue
instanceof Long
|| rOperandValue
instanceof Long
) {
209 final long r
= ((Number
)rOperandValue
).longValue();
210 final long l
= ((Number
)lOperandValue
).longValue();
211 checkDivisionOverflow(l
, r
, Long
.MIN_VALUE
, expression
);
212 value
= r
== 0 ?
null : Long
.valueOf(l
/ r
);
215 final int r
= ((Number
)rOperandValue
).intValue();
216 final int l
= ((Number
)lOperandValue
).intValue();
217 checkDivisionOverflow(l
, r
, Integer
.MIN_VALUE
, expression
);
218 value
= r
== 0 ?
null : Integer
.valueOf(l
/ r
);
222 else if (tokenType
== JavaTokenType
.PERC
) {
223 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
224 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
225 if (lOperandValue
instanceof Number
&& rOperandValue
instanceof Number
) {
226 double rVal
= ((Number
)rOperandValue
).doubleValue();
227 if (myThrowExceptionOnOverflow
&& rVal
== 0) throw new ConstantEvaluationOverflowException(expression
);
228 if (lOperandValue
instanceof Double
|| rOperandValue
instanceof Double
) {
229 value
= new Double(((Number
)lOperandValue
).doubleValue() % ((Number
)rOperandValue
).doubleValue());
230 checkRealNumberOverflow(value
, lOperandValue
, rOperandValue
, expression
);
232 else if (lOperandValue
instanceof Float
|| rOperandValue
instanceof Float
) {
233 value
= new Float(((Number
)lOperandValue
).floatValue() % ((Number
)rOperandValue
).floatValue());
234 checkRealNumberOverflow(value
, lOperandValue
, rOperandValue
, expression
);
236 else if (lOperandValue
instanceof Long
|| rOperandValue
instanceof Long
) {
237 final long l
= ((Number
)lOperandValue
).longValue();
238 final long r
= ((Number
)rOperandValue
).longValue();
239 checkDivisionOverflow(l
, r
, Long
.MIN_VALUE
, expression
);
240 value
= r
== 0 ?
null : Long
.valueOf(l
% r
);
243 final int l
= ((Number
)lOperandValue
).intValue();
244 final int r
= ((Number
)rOperandValue
).intValue();
245 checkDivisionOverflow(l
, r
, Integer
.MIN_VALUE
, expression
);
246 value
= r
== 0 ?
null : Integer
.valueOf(l
% r
);
250 else if (tokenType
== JavaTokenType
.LTLT
) {
251 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
252 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
253 if (isIntegral(lOperandValue
) && isIntegral(rOperandValue
)) {
254 if (lOperandValue
instanceof Long
) {
255 value
= Long
.valueOf(((Number
)lOperandValue
).longValue() << ((Number
)rOperandValue
).longValue());
258 value
= Integer
.valueOf(((Number
)lOperandValue
).intValue() << ((Number
)rOperandValue
).intValue());
262 else if (tokenType
== JavaTokenType
.GTGT
) {
263 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
264 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
265 if (isIntegral(lOperandValue
) && isIntegral(rOperandValue
)) {
266 if (lOperandValue
instanceof Long
) {
267 value
= Long
.valueOf(((Number
)lOperandValue
).longValue() >> ((Number
)rOperandValue
).longValue());
270 value
= Integer
.valueOf(((Number
)lOperandValue
).intValue() >> ((Number
)rOperandValue
).intValue());
274 else if (tokenType
== JavaTokenType
.GTGTGT
) {
275 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
276 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
277 if (isIntegral(lOperandValue
) && isIntegral(rOperandValue
)) {
278 if (lOperandValue
instanceof Long
) {
279 value
= Long
.valueOf(((Number
)lOperandValue
).longValue() >>> ((Number
)rOperandValue
).longValue());
282 value
= Integer
.valueOf(((Number
)lOperandValue
).intValue() >>> ((Number
)rOperandValue
).intValue());
286 else if (tokenType
== JavaTokenType
.AND
) {
287 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
288 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
289 if (isIntegral(lOperandValue
) && isIntegral(rOperandValue
)) {
290 if (lOperandValue
instanceof Long
|| rOperandValue
instanceof Long
) {
291 value
= Long
.valueOf(((Number
)lOperandValue
).longValue() & ((Number
)rOperandValue
).longValue());
294 value
= Integer
.valueOf(((Number
)lOperandValue
).intValue() & ((Number
)rOperandValue
).intValue());
297 else if (lOperandValue
instanceof Boolean
&& rOperandValue
instanceof Boolean
) {
298 value
= Boolean
.valueOf(((Boolean
)lOperandValue
).booleanValue() && ((Boolean
)rOperandValue
).booleanValue());
301 else if (tokenType
== JavaTokenType
.OR
) {
302 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
303 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
304 if (isIntegral(lOperandValue
) && isIntegral(rOperandValue
)) {
305 if (lOperandValue
instanceof Long
|| rOperandValue
instanceof Long
) {
306 value
= Long
.valueOf(((Number
)lOperandValue
).longValue() | ((Number
)rOperandValue
).longValue());
309 value
= Integer
.valueOf(((Number
)lOperandValue
).intValue() | ((Number
)rOperandValue
).intValue());
312 else if (lOperandValue
instanceof Boolean
&& rOperandValue
instanceof Boolean
) {
313 value
= Boolean
.valueOf(((Boolean
)lOperandValue
).booleanValue() || ((Boolean
)rOperandValue
).booleanValue());
316 else if (tokenType
== JavaTokenType
.XOR
) {
317 if (lOperandValue
instanceof Character
) lOperandValue
= Integer
.valueOf(((Character
)lOperandValue
).charValue());
318 if (rOperandValue
instanceof Character
) rOperandValue
= Integer
.valueOf(((Character
)rOperandValue
).charValue());
319 if (isIntegral(lOperandValue
) && isIntegral(rOperandValue
)) {
320 if (lOperandValue
instanceof Long
|| rOperandValue
instanceof Long
) {
321 value
= Long
.valueOf(((Number
)lOperandValue
).longValue() ^
((Number
)rOperandValue
).longValue());
324 value
= Integer
.valueOf(((Number
)lOperandValue
).intValue() ^
((Number
)rOperandValue
).intValue());
327 else if (lOperandValue
instanceof Boolean
&& rOperandValue
instanceof Boolean
) {
328 value
= Boolean
.valueOf(((Boolean
)lOperandValue
).booleanValue() ^
((Boolean
)rOperandValue
).booleanValue());
331 else if (tokenType
== JavaTokenType
.ANDAND
) {
332 if (lOperandValue
instanceof Boolean
&& !((Boolean
)lOperandValue
).booleanValue()) {
333 myValue
= Boolean
.FALSE
;
336 if (rOperandValue
instanceof Boolean
&& !((Boolean
)rOperandValue
).booleanValue()) {
337 myValue
= Boolean
.FALSE
;
340 if (lOperandValue
instanceof Boolean
&& rOperandValue
instanceof Boolean
) {
341 value
= Boolean
.valueOf(((Boolean
)lOperandValue
).booleanValue() && ((Boolean
)rOperandValue
).booleanValue());
344 else if (tokenType
== JavaTokenType
.OROR
) {
345 if (lOperandValue
instanceof Boolean
&& ((Boolean
)lOperandValue
).booleanValue()) {
346 myValue
= Boolean
.TRUE
;
349 if (rOperandValue
instanceof Boolean
&& ((Boolean
)rOperandValue
).booleanValue()) {
350 myValue
= Boolean
.TRUE
;
353 if (lOperandValue
instanceof Boolean
&& rOperandValue
instanceof Boolean
) {
354 value
= Boolean
.valueOf(((Boolean
)lOperandValue
).booleanValue() || ((Boolean
)rOperandValue
).booleanValue());
361 private Object
accept(PsiElement element
) {
362 if (element
== null) return null;
364 Key
<CachedValue
<ConcurrentMap
<PsiElement
, Object
>>> key
= myThrowExceptionOnOverflow ?
365 CONSTANT_VALUE_WITH_OVERFLOW_MAP_KEY
:
366 CONSTANT_VALUE_WO_OVERFLOW_MAP_KEY
;
367 return calculateWithCaching(key
, element
);
370 private static final CachedValueProvider
<ConcurrentMap
<PsiElement
,Object
>> PROVIDER
= new CachedValueProvider
<ConcurrentMap
<PsiElement
,Object
>>() {
371 public Result
<ConcurrentMap
<PsiElement
,Object
>> compute() {
372 ConcurrentMap
<PsiElement
, Object
> value
= new ConcurrentSoftHashMap
<PsiElement
, Object
>();
373 return Result
.create(value
, PsiModificationTracker
.MODIFICATION_COUNT
);
376 private Object
calculateWithCaching(final Key
<CachedValue
<ConcurrentMap
<PsiElement
, Object
>>> key
, @NotNull PsiElement element
) {
377 ConcurrentMap
<PsiElement
, Object
> map
= PsiManager
.getInstance(myProject
).getCachedValuesManager().getCachedValue(myProject
, key
, PROVIDER
, false);
378 Object value
= map
.get(element
);
381 element
.accept(this);
382 value
= ConcurrencyUtil
.cacheOrGet(map
, element
, myValue
== null ? NO_VALUE
: myValue
);
384 if (value
== NO_VALUE
) {
390 @Override public void visitTypeCastExpression(PsiTypeCastExpression expression
) {
391 final PsiTypeElement castTypeElement
= expression
.getCastType();
392 if(castTypeElement
== null || expression
.getOperand() == null) {
396 PsiType castType
= castTypeElement
.getType();
398 Object operand
= accept(expression
.getOperand());
400 myValue
= ConstantExpressionUtil
.computeCastTo(operand
, castType
);
403 @Override public void visitConditionalExpression(PsiConditionalExpression expression
) {
404 if (expression
.getThenExpression() == null || expression
.getElseExpression() == null) {
409 Object condition
= accept(expression
.getCondition());
410 Object thenExpr
= accept(expression
.getThenExpression());
411 Object elseExpr
= accept(expression
.getElseExpression());
414 if (condition
instanceof Boolean
&& thenExpr
!= null && elseExpr
!= null) {
415 value
= ((Boolean
) condition
).booleanValue() ? thenExpr
: elseExpr
;
421 @Override public void visitPrefixExpression(PsiPrefixExpression expression
) {
422 if (expression
.getOperand() == null) {
426 Object operand
= accept(expression
.getOperand());
427 if (operand
== null) {
431 IElementType tokenType
= expression
.getOperationSign().getTokenType();
433 if (tokenType
== JavaTokenType
.MINUS
) {
434 if (operand
instanceof Character
) operand
= Integer
.valueOf(((Character
)operand
).charValue());
435 if (operand
instanceof Number
) {
436 if (operand
instanceof Double
) {
437 value
= new Double(-((Number
)operand
).doubleValue());
438 checkRealNumberOverflow(value
, null, null, expression
);
440 else if (operand
instanceof Float
) {
441 value
= new Float(-((Number
)operand
).floatValue());
442 checkRealNumberOverflow(value
, null, null, expression
);
444 else if (operand
instanceof Long
) {
445 value
= Long
.valueOf(-((Number
)operand
).longValue());
446 if (myThrowExceptionOnOverflow
447 && !(expression
.getOperand() instanceof PsiLiteralExpression
)
448 && ((Number
)operand
).longValue() == Long
.MIN_VALUE
) {
449 throw new ConstantEvaluationOverflowException(expression
);
453 value
= Integer
.valueOf(-((Number
)operand
).intValue());
454 if (myThrowExceptionOnOverflow
455 && !(expression
.getOperand() instanceof PsiLiteralExpression
)
456 && ((Number
)operand
).intValue() == Integer
.MIN_VALUE
) {
457 throw new ConstantEvaluationOverflowException(expression
);
462 else if (tokenType
== JavaTokenType
.PLUS
) {
463 if (operand
instanceof Character
) operand
= Integer
.valueOf(((Character
)operand
).charValue());
464 if (operand
instanceof Number
) {
468 else if (tokenType
== JavaTokenType
.TILDE
) {
469 if (operand
instanceof Character
) operand
= Integer
.valueOf(((Character
)operand
).charValue());
470 if (isIntegral(operand
)) {
471 if (operand
instanceof Long
) {
472 value
= Long
.valueOf(~
((Number
)operand
).longValue());
475 value
= Integer
.valueOf(~
((Number
)operand
).intValue());
479 else if (tokenType
== JavaTokenType
.EXCL
) {
480 if (operand
instanceof Boolean
) {
481 value
= Boolean
.valueOf(!((Boolean
)operand
).booleanValue());
488 @Override public void visitParenthesizedExpression(PsiParenthesizedExpression expression
) {
489 myValue
= accept(expression
.getExpression());
492 @Override public void visitReferenceExpression(PsiReferenceExpression expression
) {
493 PsiExpression qualifierExpression
= expression
.getQualifierExpression();
494 while (qualifierExpression
!= null) {
495 if (!(qualifierExpression
instanceof PsiReferenceExpression
)) {
500 PsiReferenceExpression qualifier
= (PsiReferenceExpression
) qualifierExpression
;
501 final PsiElement resolved
= qualifier
.resolve();
502 if (resolved
instanceof PsiPackage
) break;
503 if (!(resolved
instanceof PsiClass
)) {
507 qualifierExpression
= ((PsiReferenceExpression
) qualifierExpression
).getQualifierExpression();
509 PsiElement resolvedExpression
= expression
.resolve();
510 if (resolvedExpression
instanceof PsiVariable
) {
511 PsiVariable variable
= (PsiVariable
) resolvedExpression
;
513 if (myVisitedVars
!= null && myVisitedVars
.contains(variable
)) {
518 Set
<PsiVariable
> oldVisitedVars
= myVisitedVars
;
519 if (myVisitedVars
== null) { myVisitedVars
= new THashSet
<PsiVariable
>(); }
521 myVisitedVars
.add(variable
);
523 if (!(variable
instanceof PsiVariableEx
)) {
528 myValue
= ((PsiVariableEx
) variable
).computeConstantValue(myVisitedVars
);
532 myVisitedVars
.remove(variable
);
533 myVisitedVars
= oldVisitedVars
;
540 private static boolean isIntegral(Object o
) {
541 return o
instanceof Long
|| o
instanceof Integer
|| o
instanceof Short
|| o
instanceof Byte
|| o
instanceof Character
;
544 private void checkDivisionOverflow(long l
, final long r
, long minValue
, PsiBinaryExpression expression
) {
545 if (!myThrowExceptionOnOverflow
) return;
546 if (r
== 0) throw new ConstantEvaluationOverflowException(expression
);
547 if (r
== -1 && l
== minValue
) throw new ConstantEvaluationOverflowException(expression
);
550 private void checkMultiplicationOverflow(long result
, long l
, long r
, PsiExpression expression
) {
551 if (!myThrowExceptionOnOverflow
) return;
552 if (r
== 0 || l
== 0) return;
553 if (result
/ r
!= l
|| ((l
< 0) ^
(r
< 0) != (result
< 0))) throw new ConstantEvaluationOverflowException(expression
);
556 private void checkAdditionOverflow(boolean resultPositive
,
558 boolean rPositive
, PsiBinaryExpression expression
) {
559 if (!myThrowExceptionOnOverflow
) return;
560 boolean overflow
= lPositive
== rPositive
&& lPositive
!= resultPositive
;
561 if (overflow
) throw new ConstantEvaluationOverflowException(expression
);
564 private void checkRealNumberOverflow(Object result
,
565 Object lOperandValue
,
566 Object rOperandValue
, PsiExpression expression
) {
567 if (!myThrowExceptionOnOverflow
) return;
568 if (lOperandValue
instanceof Float
&& ((Float
) lOperandValue
).isInfinite()) return;
569 if (lOperandValue
instanceof Double
&& ((Double
) lOperandValue
).isInfinite()) return;
570 if (rOperandValue
instanceof Float
&& ((Float
) rOperandValue
).isInfinite()) return;
571 if (rOperandValue
instanceof Double
&& ((Double
) rOperandValue
).isInfinite()) return;
573 if (result
instanceof Float
&& ((Float
) result
).isInfinite()) throw new ConstantEvaluationOverflowException(expression
);
574 if (result
instanceof Double
&& ((Double
) result
).isInfinite()) throw new ConstantEvaluationOverflowException(expression
);
577 public static Object
computeConstantExpression(PsiExpression expression
, Set
<PsiVariable
> visitedVars
, boolean throwExceptionOnOverflow
) {
578 if (expression
== null) return null;
579 ConstantExpressionEvaluator evaluator
= new ConstantExpressionEvaluator(visitedVars
, throwExceptionOnOverflow
, expression
.getProject());
580 return evaluator
.accept(expression
);