1 package com
.intellij
.psi
.impl
;
3 import com
.intellij
.openapi
.project
.Project
;
4 import com
.intellij
.openapi
.util
.Factory
;
5 import com
.intellij
.openapi
.util
.Key
;
6 import com
.intellij
.psi
.*;
7 import com
.intellij
.psi
.util
.CachedValue
;
8 import com
.intellij
.psi
.util
.CachedValueProvider
;
9 import com
.intellij
.psi
.util
.PsiModificationTracker
;
10 import com
.intellij
.util
.ConcurrencyUtil
;
11 import com
.intellij
.util
.containers
.ConcurrentSoftHashMap
;
12 import org
.jetbrains
.annotations
.NotNull
;
13 import org
.jetbrains
.annotations
.Nullable
;
16 import java
.util
.concurrent
.ConcurrentMap
;
18 public class ConstantExpressionEvaluator
extends JavaRecursiveElementWalkingVisitor
{
19 private final Factory
<ConcurrentMap
<PsiElement
, Object
>> myMapFactory
;
20 private final Project myProject
;
22 private static final Key
<CachedValue
<ConcurrentMap
<PsiElement
,Object
>>> CONSTANT_VALUE_WO_OVERFLOW_MAP_KEY
= Key
.create("CONSTANT_VALUE_WO_OVERFLOW_MAP_KEY");
23 private static final Key
<CachedValue
<ConcurrentMap
<PsiElement
,Object
>>> CONSTANT_VALUE_WITH_OVERFLOW_MAP_KEY
= Key
.create("CONSTANT_VALUE_WITH_OVERFLOW_MAP_KEY");
24 private static final Object NO_VALUE
= new Object();
25 private final ConstantExpressionVisitor myConstantExpressionVisitor
;
27 private ConstantExpressionEvaluator(Set
<PsiVariable
> visitedVars
, final boolean throwExceptionOnOverflow
, final Project project
, final PsiConstantEvaluationHelper
.AuxEvaluator auxEvaluator
) {
28 myMapFactory
= auxEvaluator
!= null ?
new Factory
<ConcurrentMap
<PsiElement
, Object
>>() {
29 public ConcurrentMap
<PsiElement
, Object
> create() {
30 return auxEvaluator
.getCacheMap(throwExceptionOnOverflow
);
32 } : new Factory
<ConcurrentMap
<PsiElement
, Object
>>() {
33 public ConcurrentMap
<PsiElement
, Object
> create() {
34 final Key
<CachedValue
<ConcurrentMap
<PsiElement
, Object
>>> key
=
35 throwExceptionOnOverflow ? CONSTANT_VALUE_WITH_OVERFLOW_MAP_KEY
: CONSTANT_VALUE_WO_OVERFLOW_MAP_KEY
;
36 return PsiManager
.getInstance(myProject
).getCachedValuesManager().getCachedValue(myProject
, key
, PROVIDER
, false);
40 myConstantExpressionVisitor
= new ConstantExpressionVisitor(visitedVars
, throwExceptionOnOverflow
, auxEvaluator
);
45 protected void elementFinished(PsiElement element
) {
46 Object value
= getCached(element
);
48 Object result
= myConstantExpressionVisitor
.handle(element
);
49 cache(element
, result
);
54 public void visitElement(PsiElement element
) {
55 Object value
= getCached(element
);
57 super.visitElement(element
);
58 // will cache back in elementFinished()
61 ConstantExpressionVisitor
.store(element
, value
== NO_VALUE ?
null : value
);
65 private static final CachedValueProvider
<ConcurrentMap
<PsiElement
,Object
>> PROVIDER
= new CachedValueProvider
<ConcurrentMap
<PsiElement
,Object
>>() {
66 public Result
<ConcurrentMap
<PsiElement
,Object
>> compute() {
67 ConcurrentMap
<PsiElement
, Object
> value
= new ConcurrentSoftHashMap
<PsiElement
, Object
>();
68 return Result
.create(value
, PsiModificationTracker
.MODIFICATION_COUNT
);
72 private Object
getCached(@NotNull PsiElement element
) {
73 return map().get(element
);
75 private Object
cache(@NotNull PsiElement element
, @Nullable Object value
) {
76 value
= ConcurrencyUtil
.cacheOrGet(map(), element
, value
== null ? NO_VALUE
: value
);
77 if (value
== NO_VALUE
) {
84 private ConcurrentMap
<PsiElement
, Object
> map() {
85 return myMapFactory
.create();
88 public static Object
computeConstantExpression(PsiExpression expression
, @Nullable Set
<PsiVariable
> visitedVars
, boolean throwExceptionOnOverflow
) {
89 return computeConstantExpression(expression
, visitedVars
, throwExceptionOnOverflow
, null);
92 public static Object
computeConstantExpression(PsiExpression expression
, @Nullable Set
<PsiVariable
> visitedVars
, boolean throwExceptionOnOverflow
,
93 final PsiConstantEvaluationHelper
.AuxEvaluator auxEvaluator
) {
94 if (expression
== null) return null;
96 ConstantExpressionEvaluator evaluator
= new ConstantExpressionEvaluator(visitedVars
, throwExceptionOnOverflow
, expression
.getProject(),
98 expression
.accept(evaluator
);
99 Object cached
= evaluator
.getCached(expression
);
100 return cached
== NO_VALUE ?
null : cached
;
103 public static Object
computeConstantExpression(PsiExpression expression
, boolean throwExceptionOnOverflow
) {
104 return computeConstantExpression(expression
, null, throwExceptionOnOverflow
);