DefaultActionGroup.addSeparator(String)
[fedora-idea.git] / source / com / intellij / psi / impl / ConstantExpressionEvaluator.java
blob064c02e99168d1c439b25957996bdea490a884d4
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;
14 import java.util.Set;
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;
33 myProject = project;
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) {
44 myValue = null;
45 return;
48 Object rOperandValue = accept(expression.getROperand());
49 if (rOperandValue == null) {
50 myValue = null;
51 return;
54 PsiJavaToken operationSign = expression.getOperationSign();
55 final IElementType tokenType = operationSign.getTokenType();
57 Object value = null;
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());
116 else {
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);
135 else {
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);
162 else {
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);
188 else {
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);
214 else {
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);
242 else {
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());
257 else {
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());
269 else {
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());
281 else {
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());
293 else {
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());
308 else {
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());
323 else {
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;
334 return;
336 if (rOperandValue instanceof Boolean && !((Boolean)rOperandValue).booleanValue()) {
337 myValue = Boolean.FALSE;
338 return;
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;
347 return;
349 if (rOperandValue instanceof Boolean && ((Boolean)rOperandValue).booleanValue()) {
350 myValue = Boolean.TRUE;
351 return;
353 if (lOperandValue instanceof Boolean && rOperandValue instanceof Boolean) {
354 value = Boolean.valueOf(((Boolean)lOperandValue).booleanValue() || ((Boolean)rOperandValue).booleanValue());
358 myValue = value;
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);
379 if (value == null) {
380 myValue = null;
381 element.accept(this);
382 value = ConcurrencyUtil.cacheOrGet(map, element, myValue == null ? NO_VALUE : myValue);
384 if (value == NO_VALUE) {
385 value = null;
387 return value;
390 @Override public void visitTypeCastExpression(PsiTypeCastExpression expression) {
391 final PsiTypeElement castTypeElement = expression.getCastType();
392 if(castTypeElement == null || expression.getOperand() == null) {
393 myValue = null;
394 return;
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) {
405 myValue = null;
406 return;
409 Object condition = accept(expression.getCondition());
410 Object thenExpr = accept(expression.getThenExpression());
411 Object elseExpr = accept(expression.getElseExpression());
413 Object value = null;
414 if (condition instanceof Boolean && thenExpr != null && elseExpr != null) {
415 value = ((Boolean) condition).booleanValue() ? thenExpr : elseExpr;
418 myValue = value;
421 @Override public void visitPrefixExpression(PsiPrefixExpression expression) {
422 if (expression.getOperand() == null) {
423 myValue = null;
424 return;
426 Object operand = accept(expression.getOperand());
427 if (operand == null) {
428 myValue = null;
429 return;
431 IElementType tokenType = expression.getOperationSign().getTokenType();
432 Object value = null;
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);
452 else {
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) {
465 value = operand;
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());
474 else {
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());
485 myValue = value;
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)) {
496 myValue = null;
497 return;
500 PsiReferenceExpression qualifier = (PsiReferenceExpression) qualifierExpression;
501 final PsiElement resolved = qualifier.resolve();
502 if (resolved instanceof PsiPackage) break;
503 if (!(resolved instanceof PsiClass)) {
504 myValue = null;
505 return;
507 qualifierExpression = ((PsiReferenceExpression) qualifierExpression).getQualifierExpression();
509 PsiElement resolvedExpression = expression.resolve();
510 if (resolvedExpression instanceof PsiVariable) {
511 PsiVariable variable = (PsiVariable) resolvedExpression;
512 // avoid cycles
513 if (myVisitedVars != null && myVisitedVars.contains(variable)) {
514 myValue = null;
515 return;
518 Set<PsiVariable> oldVisitedVars = myVisitedVars;
519 if (myVisitedVars == null) { myVisitedVars = new THashSet<PsiVariable>(); }
521 myVisitedVars.add(variable);
522 try {
523 if (!(variable instanceof PsiVariableEx)) {
524 myValue = null; //?
525 return;
528 myValue = ((PsiVariableEx) variable).computeConstantValue(myVisitedVars);
529 return;
531 finally {
532 myVisitedVars.remove(variable);
533 myVisitedVars = oldVisitedVars;
537 myValue = null;
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,
557 boolean lPositive,
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);