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
;
32 * Computes the constant value of an expression while considering the substitution annotation for non-compile-time
33 * constant expressions.
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() {
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
) {
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
) {
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
81 for (PsiExpression value
: values
) {
82 final Object computedValue
= auxEvaluator
.computeExpression(value
, this);
83 if (computedValue
!= null) {
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() {
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();
113 public ConcurrentMap
<PsiElement
, Object
> getCacheMap(final boolean overflow
) {
115 //return PsiManager.getInstance(project).getCachedValuesManager().getCachedValue(project, COMPUTED_MAP_KEY, PROVIDER, false);
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");