blob: 4e9f186e1ca5a388a8a6163c2781d95449c3c769 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* 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 com.intellij.codeInspection.dataFlow;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.MethodReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.CommonProcessors;
import com.intellij.util.containers.hash.HashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Set;
public class StringExpressionHelper {
@Nullable
public static Pair<PsiElement, String> evaluateExpression(@NotNull PsiElement expression) {
return evaluateExpression(expression, new HashSet<PsiElement>());
}
@Nullable
public static Pair<PsiElement, String> evaluateExpression(@NotNull PsiElement expression, @NotNull Collection<PsiElement> visited) {
visited.add(expression);
if (expression instanceof PsiLiteralExpression) {
return evaluatePsiLiteralExpression(expression);
}
if (expression instanceof PsiReferenceExpression) {
PsiElement resolve = ((PsiReferenceExpression)expression).resolve();
if (resolve instanceof PsiVariable) {
PsiExpression initializer = ((PsiVariable)resolve).getInitializer();
if (initializer != null) {
Pair<PsiElement, String> expr = evaluateExpression(initializer, visited);
if (expr != null) return expr;
}
}
}
if (expression instanceof PsiMethodCallExpression) {
final PsiElement element = ((PsiMethodCallExpression)expression).getMethodExpression().resolve();
if (element instanceof PsiMethod) {
PsiCodeBlock body = ((PsiMethod)element).getBody();
if (body != null) {
final Set<PsiExpression> returns = new com.intellij.util.containers.HashSet<PsiExpression>();
body.accept(new JavaRecursiveElementVisitor() {
public void visitClass(PsiClass aClass) {}
public void visitLambdaExpression(PsiLambdaExpression expression) {}
@Override
public void visitReturnStatement(PsiReturnStatement statement) {
PsiExpression returnValue = statement.getReturnValue();
if (returnValue != null) {
returns.add(returnValue);
}
}
});
for (PsiExpression psiExpression : returns) {
Pair<PsiElement, String> pair = evaluateExpression(psiExpression, visited);
if (pair != null) {
return pair;
}
}
}
return evaluateExpression(element, visited);
}
return null;
}
Pair<PsiElement, String> constantExpression = evaluateConstantExpression(expression);
if (constantExpression != null) {
return constantExpression;
}
if (expression instanceof PsiBinaryExpression) {
// a="a"; b="b" return a+b;
PsiBinaryExpression binaryExpression = (PsiBinaryExpression)expression;
return evaluatePolyadicExpressions(expression, visited, binaryExpression.getLOperand(), binaryExpression.getROperand());
}
if (expression instanceof PsiPolyadicExpression) {
// a="a"; b="b"; c="c" return a+b+c;
return evaluatePolyadicExpressions(expression, visited, ((PsiPolyadicExpression)expression).getOperands());
}
Collection<? extends PsiElement> elements = DfaUtil.getPossibleInitializationElements(expression);
for (PsiElement element : elements) {
if (!visited.contains(element)) {
Pair<PsiElement, String> expr = evaluateExpression(element);
if (expr != null) return expr;
}
}
return null;
}
@Nullable
private static Pair<PsiElement, String> evaluatePolyadicExpressions(@NotNull PsiElement expression,
@NotNull Collection<PsiElement> visited,
@NotNull PsiExpression... operands) {
StringBuilder sb = new StringBuilder();
for (PsiExpression operand : operands) {
Pair<PsiElement, String> pair = evaluateExpression(operand, visited);
if (pair == null) return null;
sb.append(pair.second);
}
return Pair.create(expression, sb.toString());
}
@Nullable
public static Pair<PsiElement, String> evaluatePsiLiteralExpression(@NotNull PsiElement expression) {
return Pair.create(expression, ElementManipulators.getValueText(expression));
}
@Nullable
public static Pair<PsiElement, String> evaluateConstantExpression(@NotNull PsiElement expression) {
PsiConstantEvaluationHelper helper = JavaPsiFacade.getInstance(expression.getProject()).getConstantEvaluationHelper();
Object result = helper.computeConstantExpression(expression);
if (result instanceof String) {
return Pair.create(expression, (String)result);
}
return null;
}
@NotNull
public static Set<Pair<PsiElement, String>> searchStringExpressions(@NotNull final PsiMethod psiMethod,
@NotNull SearchScope searchScope,
int expNum) {
Set<Pair<PsiElement, String>> pairs = new com.intellij.util.containers.HashSet<Pair<PsiElement, String>>();
for (PsiMethodCallExpression methodCallExpression : searchMethodCalls(psiMethod, searchScope)) {
final PsiExpression[] expressions = methodCallExpression.getArgumentList().getExpressions();
if (expressions.length > expNum) {
final PsiExpression expression = expressions[expNum];
Pair<PsiElement, String> pair = evaluateExpression(expression);
if (pair != null) {
pairs.add(pair);
}
}
}
return pairs;
}
@NotNull
public static Set<PsiMethodCallExpression> searchMethodCalls(@NotNull final PsiMethod psiMethod, @NotNull SearchScope searchScope) {
final Set<PsiMethodCallExpression> callExpressions = new com.intellij.util.containers.HashSet<PsiMethodCallExpression>();
final CommonProcessors.CollectUniquesProcessor<PsiReference> consumer = new CommonProcessors.CollectUniquesProcessor<PsiReference>();
MethodReferencesSearch.search(psiMethod, searchScope, true).forEach(consumer);
for (PsiReference psiReference : consumer.getResults()) {
final PsiMethodCallExpression methodCallExpression =
PsiTreeUtil.getParentOfType(psiReference.getElement(), PsiMethodCallExpression.class);
if (methodCallExpression != null) {
callExpressions.add(methodCallExpression);
}
}
return callExpressions;
}
}