IDEA-51945
[fedora-idea.git] / plugins / IntelliLang / src / org / intellij / plugins / intelliLang / util / SubstitutedExpressionEvaluationHelper.java
blobc71decb9f1fd9acf16b06395fabab7dc095a2d23
1 /*
2 * Copyright 2006 Sascha Weinreuter
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.intellij.plugins.intelliLang.util;
18 import com.intellij.codeInsight.AnnotationUtil;
19 import com.intellij.codeInspection.dataFlow.DfaUtil;
20 import com.intellij.openapi.project.Project;
21 import com.intellij.psi.*;
22 import com.intellij.util.containers.ConcurrentHashMap;
23 import org.intellij.plugins.intelliLang.Configuration;
24 import org.jetbrains.annotations.Nullable;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.concurrent.ConcurrentMap;
31 /**
32 * Computes the constant value of an expression while considering the substitution annotation for non-compile-time
33 * constant expressions.
34 * <p/>
35 * This is a quite simplified implementation at the moment.
37 public class SubstitutedExpressionEvaluationHelper {
39 private final PsiConstantEvaluationHelper myHelper;
40 private final Configuration myConfiguration;
42 public SubstitutedExpressionEvaluationHelper(final Project project) {
43 myHelper = JavaPsiFacade.getInstance(project).getConstantEvaluationHelper();
44 myConfiguration = Configuration.getInstance();
47 public Object computeExpression(final PsiExpression e, final List<PsiExpression> uncomputables) {
48 return computeExpression(e, myConfiguration.isUseDfaIfAvailable(), myConfiguration.isIncludeUncomputablesAsLiterals(), uncomputables);
51 public Object computeExpression(final PsiExpression e, final boolean useDfa, final boolean includeUncomputablesAsLiterals, final List<PsiExpression> uncomputables) {
52 final ConcurrentMap<PsiElement, Object> map = new ConcurrentHashMap<PsiElement, Object>();
53 //if (true) return myHelper.computeConstantExpression(e, false);
54 return myHelper.computeExpression(e, false, new PsiConstantEvaluationHelper.AuxEvaluator() {
55 @Nullable
56 public Object computeExpression(final PsiExpression o, final PsiConstantEvaluationHelper.AuxEvaluator auxEvaluator) {
57 PsiType resolvedType = null;
58 if (o instanceof PsiMethodCallExpression) {
59 final PsiMethodCallExpression c = (PsiMethodCallExpression)o;
60 final PsiMethod m = (PsiMethod)c.getMethodExpression().resolve();
61 final PsiType returnType = m != null? m.getReturnType() : null;
62 if (returnType != null && returnType != PsiType.VOID) {
63 // find substitution
64 final Object substituted = calcSubstituted(m);
65 if (substituted != null) return substituted;
67 resolvedType = returnType;
69 else if (o instanceof PsiReferenceExpression) {
70 final PsiElement resolved = ((PsiReferenceExpression)o).resolve();
71 if (resolved instanceof PsiModifierListOwner) {
72 // find substitution
73 final Object substituted = calcSubstituted((PsiModifierListOwner)resolved);
74 if (substituted != null) return substituted;
75 if (resolved instanceof PsiVariable) {
76 resolvedType = ((PsiVariable)resolved).getType();
77 final Collection<PsiExpression> values =
78 !useDfa? Collections.<PsiExpression>emptyList() : DfaUtil.getCachedVariableValues((PsiVariable)resolved, o);
79 // return the first computed value as far as we do not support multiple injection
80 if (values != null) {
81 for (PsiExpression value : values) {
82 final Object computedValue = auxEvaluator.computeExpression(value, this);
83 if (computedValue != null) {
84 return computedValue;
91 if (uncomputables != null) uncomputables.add(o);
92 if (includeUncomputablesAsLiterals) {
93 if (resolvedType != null) {
94 if (PsiPrimitiveType.DOUBLE.isAssignableFrom(resolvedType)) return 1; // magic number!
96 final StringBuilder sb = new StringBuilder();
97 o.accept(new PsiRecursiveElementWalkingVisitor() {
98 @Override
99 public void visitElement(PsiElement element) {
100 if (element instanceof PsiExpressionList) return;
101 if (element instanceof PsiIdentifier) {
102 if (sb.length() > 0) sb.append(".");
103 sb.append(element.getText());
105 super.visitElement(element);
108 return sb.toString();
110 return null;
113 public ConcurrentMap<PsiElement, Object> getCacheMap(final boolean overflow) {
114 return map;
115 //return PsiManager.getInstance(project).getCachedValuesManager().getCachedValue(project, COMPUTED_MAP_KEY, PROVIDER, false);
120 @Nullable
121 private Object calcSubstituted(final PsiModifierListOwner owner) {
122 final PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, myConfiguration.getSubstAnnotationPair().second);
123 if (annotation != null) {
124 return AnnotationUtilEx.calcAnnotationValue(annotation, "value");
126 return null;