blob: 0a583d2d3b8f55f662131afd28e10302075ab3bd [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.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* Helper class that can compute the prefix and suffix of an expression inside a binary (usually additive) expression
* that computes the values not only for compile-time constants, but also for elements annotated with a substitution
* annotation.
*
* @see org.intellij.plugins.intelliLang.util.SubstitutedExpressionEvaluationHelper
*/
public class ContextComputationProcessor {
private final SubstitutedExpressionEvaluationHelper myEvaluationHelper;
private ContextComputationProcessor(final Project project) {
myEvaluationHelper = new SubstitutedExpressionEvaluationHelper(project);
}
@NotNull
public static List<Object> collectOperands(@NotNull final String prefix, final String suffix, final Ref<Boolean> unparsable, final PsiElement[] operands) {
final ArrayList<Object> result = new ArrayList<Object>();
final ContextComputationProcessor processor = new ContextComputationProcessor(operands[0].getProject());
addStringFragment(prefix, result);
for (PsiElement operand : operands) {
processor.collectOperands(operand, result, unparsable);
}
addStringFragment(suffix, result);
return result;
}
private static void addStringFragment(final String string, final List<Object> result) {
if (StringUtil.isEmpty(string)) return;
final int size = result.size();
final Object last = size > 0? result.get(size -1) : null;
if (last instanceof String) {
result.set(size - 1, last + string);
}
else {
result.add(string);
}
}
public void collectOperands(final PsiElement expression, final List<Object> result, final Ref<Boolean> unparsable) {
if (expression instanceof PsiParenthesizedExpression) {
collectOperands(((PsiParenthesizedExpression)expression).getExpression(), result, unparsable);
}
else if (expression instanceof PsiTypeCastExpression) {
collectOperands(((PsiTypeCastExpression)expression).getOperand(), result, unparsable);
}
else if (expression instanceof PsiConditionalExpression) {
unparsable.set(Boolean.TRUE);
collectOperands(((PsiConditionalExpression)expression).getThenExpression(), result, unparsable);
addStringFragment(" ", result); // do not glue branches together
collectOperands(((PsiConditionalExpression)expression).getElseExpression(), result, unparsable);
}
else if (expression instanceof PsiPolyadicExpression &&
((PsiPolyadicExpression)expression).getOperationTokenType() == JavaTokenType.PLUS) {
final PsiPolyadicExpression binaryExpression = (PsiPolyadicExpression)expression;
for (PsiExpression operand : binaryExpression.getOperands()) {
collectOperands(operand, result, unparsable);
}
}
else if (expression instanceof PsiAssignmentExpression &&
((PsiAssignmentExpression)expression).getOperationTokenType() == JavaTokenType.PLUSEQ) {
unparsable.set(Boolean.TRUE);
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expression;
collectOperands(assignmentExpression.getLExpression(), result, unparsable);
collectOperands(assignmentExpression.getRExpression(), result, unparsable);
}
else if (PsiUtilEx.isStringOrCharacterLiteral(expression)) {
result.add(expression);
}
else if (expression instanceof PsiExpression) {
final SmartList<PsiExpression> uncomputables = new SmartList<PsiExpression>();
final Object o = myEvaluationHelper.computeExpression((PsiExpression)expression, uncomputables);
// in many languages 'null' is a reserved word
addStringFragment(o == null? "missingValue" : String.valueOf(o), result);
if (uncomputables.size() > 0) {
unparsable.set(Boolean.TRUE);
}
}
else {
unparsable.set(Boolean.TRUE);
result.add(expression);
}
}
@NotNull
public static PsiElement getTopLevelInjectionTarget(@NotNull final PsiElement host) {
PsiElement target = host;
PsiElement parent = target.getParent();
for (; parent != null; target = parent, parent = target.getParent()) {
if (parent instanceof PsiPolyadicExpression) continue;
if (parent instanceof PsiParenthesizedExpression) continue;
if (parent instanceof PsiConditionalExpression && ((PsiConditionalExpression)parent).getCondition() != target) continue;
if (parent instanceof PsiArrayInitializerMemberValue) continue;
if (parent instanceof PsiArrayInitializerExpression) {
parent = parent.getParent(); continue;
}
break;
}
return target;
}
}