customizable value calculation
[fedora-idea.git] / source / com / intellij / psi / impl / ConstantExpressionEvaluator.java
blobe0c260168160c5853720964e8f47cafca5812026
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;
15 import java.util.Set;
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);
39 myProject = project;
40 myConstantExpressionVisitor = new ConstantExpressionVisitor(visitedVars, throwExceptionOnOverflow, auxEvaluator);
44 @Override
45 protected void elementFinished(PsiElement element) {
46 Object value = getCached(element);
47 if (value == null) {
48 Object result = myConstantExpressionVisitor.handle(element);
49 cache(element, result);
53 @Override
54 public void visitElement(PsiElement element) {
55 Object value = getCached(element);
56 if (value == null) {
57 super.visitElement(element);
58 // will cache back in elementFinished()
60 else {
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) {
78 value = null;
80 return value;
83 @NotNull
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(),
97 auxEvaluator);
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);