blob: fcb00ffeeeda90de374fd6b141681098eecf31d6 [file] [log] [blame]
/*
* Copyright 2006 Sascha Weinreuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.intellij.plugins.intelliLang.util;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInspection.dataFlow.DfaPsiUtil;
import com.intellij.codeInspection.dataFlow.DfaUtil;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.util.containers.ConcurrentHashMap;
import org.intellij.plugins.intelliLang.Configuration;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
/**
* Computes the constant value of an expression while considering the substitution annotation for non-compile-time
* constant expressions.
* <p/>
* This is a quite simplified implementation at the moment.
*/
public class SubstitutedExpressionEvaluationHelper {
private final PsiConstantEvaluationHelper myHelper;
private final Configuration myConfiguration;
public SubstitutedExpressionEvaluationHelper(final Project project) {
myHelper = JavaPsiFacade.getInstance(project).getConstantEvaluationHelper();
myConfiguration = Configuration.getInstance();
}
public Object computeExpression(final PsiExpression e, final List<PsiExpression> uncomputables) {
return computeExpression(e, myConfiguration.getAdvancedConfiguration().getDfaOption(), myConfiguration.getAdvancedConfiguration().isIncludeUncomputablesAsLiterals(), uncomputables);
}
public Object computeExpression(final PsiExpression e, final Configuration.DfaOption dfaOption, final boolean includeUncomputablesAsLiterals, final List<PsiExpression> uncomputables) {
final ConcurrentMap<PsiElement, Object> map = new ConcurrentHashMap<PsiElement, Object>();
//if (true) return myHelper.computeConstantExpression(e, false);
return myHelper.computeExpression(e, false, new PsiConstantEvaluationHelper.AuxEvaluator() {
@Nullable
public Object computeExpression(final PsiExpression o, final PsiConstantEvaluationHelper.AuxEvaluator auxEvaluator) {
PsiType resolvedType = null;
if (o instanceof PsiMethodCallExpression) {
final PsiMethodCallExpression c = (PsiMethodCallExpression)o;
final PsiMethod m = (PsiMethod)c.getMethodExpression().resolve();
final PsiType returnType = m != null? m.getReturnType() : null;
if (returnType != null && returnType != PsiType.VOID) {
// find substitution
final Object substituted = calcSubstituted(m);
if (substituted != null) return substituted;
}
resolvedType = returnType;
}
else if (o instanceof PsiReferenceExpression) {
final PsiElement resolved = ((PsiReferenceExpression)o).resolve();
if (resolved instanceof PsiModifierListOwner) {
// find substitution
final Object substituted = calcSubstituted((PsiModifierListOwner)resolved);
if (substituted != null) return substituted;
if (resolved instanceof PsiVariable) {
final PsiVariable psiVariable = (PsiVariable)resolved;
resolvedType = psiVariable.getType();
final Collection<PsiExpression> values;
if (dfaOption == Configuration.DfaOption.ASSIGNMENTS) {
values = DfaPsiUtil.getVariableAssignmentsInFile(psiVariable, true, o);
}
else if (dfaOption == Configuration.DfaOption.DFA) {
final Collection<PsiExpression> realValues = DfaUtil.getCachedVariableValues(psiVariable, o);
values = realValues == null? DfaPsiUtil.getVariableAssignmentsInFile(psiVariable, true, o) : realValues;
}
else {
values = Collections.<PsiExpression>emptyList();
}
// return the first computed value as far as we do not support multiple injection
for (PsiExpression value : values) {
final Object computedValue = auxEvaluator.computeExpression(value, this);
if (computedValue != null) {
return computedValue;
}
}
}
}
}
if (uncomputables != null) uncomputables.add(o);
if (includeUncomputablesAsLiterals) {
if (resolvedType != null) {
if (PsiPrimitiveType.DOUBLE.isAssignableFrom(resolvedType)) return 1; // magic number!
}
final StringBuilder sb = new StringBuilder();
o.accept(new PsiRecursiveElementWalkingVisitor() {
@Override
public void visitElement(PsiElement element) {
if (element instanceof PsiExpressionList) return;
if (element instanceof PsiIdentifier) {
if (sb.length() > 0) sb.append(".");
sb.append(element.getText());
}
super.visitElement(element);
}
});
return sb.toString();
}
return null;
}
public ConcurrentMap<PsiElement, Object> getCacheMap(final boolean overflow) {
return map;
//return PsiManager.getInstance(project).getCachedValuesManager().getCachedValue(project, COMPUTED_MAP_KEY, PROVIDER, false);
}
});
}
@Nullable
private Object calcSubstituted(final PsiModifierListOwner owner) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, myConfiguration.getAdvancedConfiguration().getSubstAnnotationPair().second);
if (annotation != null) {
return AnnotationUtilEx.calcAnnotationValue(annotation, "value");
}
return null;
}
}