add new groupBy cases

This commit is contained in:
Roman Ivanov
2017-09-13 11:29:31 +07:00
parent 0752af3706
commit 364c5bb129
9 changed files with 497 additions and 375 deletions
@@ -30,7 +30,6 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.ig.psiutils.*;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,6 +39,9 @@ import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static com.siyeh.ig.psiutils.Java8MigrationUtils.MapCheckCondition.fromConditional;
import static com.siyeh.ig.psiutils.Java8MigrationUtils.*;
/**
* @author Tagir Valeev
*/
@@ -125,7 +127,7 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
}
boolean informationLevel =
!mySideEffects && SideEffectChecker.mayHaveSideEffects(presentValue, ex -> condition.extractGetCall(ex) != null);
condition.register(holder, informationLevel, new ReplaceWithSingleMapOperation("merge", PsiTreeUtil
register(condition, holder, informationLevel, new ReplaceWithSingleMapOperation("merge", PsiTreeUtil
.getParentOfType(absentValue, PsiMethodCallExpression.class), presentValue, noneBranch));
}
}
@@ -143,11 +145,11 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
condition.isMap(putCall.getMethodExpression().getQualifierExpression())) {
PsiExpression[] putArgs = putCall.getArgumentList().getExpressions();
if (putArgs.length != 2 || !condition.isKey(putArgs[0]) || !ExpressionUtils.isSimpleExpression(putArgs[1])) return;
condition.register(holder, false, new ReplaceWithSingleMapOperation("putIfAbsent", getCall, putArgs[1], result));
register(condition, holder, false, new ReplaceWithSingleMapOperation("putIfAbsent", getCall, putArgs[1], result));
}
if (mySuggestMapGetOrDefault && condition.isContainsKey() && ExpressionUtils.isSimpleExpression(noneExpression) &&
condition.isMapValueType(noneExpression.getType())) {
condition.register(holder, false, new ReplaceWithSingleMapOperation("getOrDefault", getCall, noneExpression, result));
condition.isMapValueType(noneExpression.getType())) {
register(condition, holder, false, new ReplaceWithSingleMapOperation("getOrDefault", getCall, noneExpression, result));
}
}
@@ -163,7 +165,7 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
PsiExpression rValue = assignment.getRExpression();
if (ExpressionUtils.isSimpleExpression(rValue) && condition.isValueReference(assignment.getLExpression()) &&
!condition.isValueReference(rValue) && condition.isMapValueType(rValue.getType())) {
condition.register(holder, false, ReplaceWithSingleMapOperation.fromIf("getOrDefault", condition, rValue));
register(condition, holder, false, ReplaceWithSingleMapOperation.fromIf("getOrDefault", condition, rValue));
}
} else if (condition.isGetNull()) {
/*
@@ -176,8 +178,7 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
PsiExpression lambdaCandidate = extractLambdaCandidate(condition, noneBranch);
if (lambdaCandidate != null && mySuggestMapComputeIfAbsent) {
boolean informationLevel = !mySideEffects && SideEffectChecker.mayHaveSideEffects(lambdaCandidate);
condition
.register(holder, informationLevel, ReplaceWithSingleMapOperation.fromIf("computeIfAbsent", condition, lambdaCandidate));
register(condition, holder, informationLevel, ReplaceWithSingleMapOperation.fromIf("computeIfAbsent", condition, lambdaCandidate));
}
if (lambdaCandidate == null) {
PsiExpression expression = extractPutValue(condition, noneBranch);
@@ -193,12 +194,11 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
}
if(replacement != null) {
if(condition.hasVariable()) {
condition.register(holder, informationLevel, ReplaceWithSingleMapOperation.fromIf(replacement, condition, expression));
register(condition, holder, informationLevel, ReplaceWithSingleMapOperation.fromIf(replacement, condition, expression));
} else {
PsiMethodCallExpression call = PsiTreeUtil.getParentOfType(expression, PsiMethodCallExpression.class);
LOG.assertTrue(call != null);
condition
.register(holder, informationLevel, new ReplaceWithSingleMapOperation(replacement, call, expression, noneBranch));
register(condition, holder, informationLevel, new ReplaceWithSingleMapOperation(replacement, call, expression, noneBranch));
}
}
}
@@ -208,133 +208,6 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
};
}
@Nullable
static PsiExpression extractLambdaCandidate(MapCheckCondition condition, PsiStatement statement) {
PsiAssignmentExpression assignment;
PsiExpression putValue = extractPutValue(condition, statement);
if(putValue != null) {
// like map.put(key, val = new ArrayList<>());
assignment = ExpressionUtils.getAssignment(putValue);
}
else {
if (!(statement instanceof PsiBlockStatement)) return null;
// like val = new ArrayList<>(); map.put(key, val);
PsiStatement[] statements = ((PsiBlockStatement)statement).getCodeBlock().getStatements();
if (statements.length != 2) return null;
putValue = extractPutValue(condition, statements[1]);
if (!condition.isValueReference(putValue)) return null;
assignment = ExpressionUtils.getAssignment(statements[0]);
}
if (assignment == null) return null;
PsiExpression lambdaCandidate = assignment.getRExpression();
if (lambdaCandidate == null || !condition.isValueReference(assignment.getLExpression())) return null;
if (!LambdaGenerationUtil.canBeUncheckedLambda(lambdaCandidate)) return null;
return lambdaCandidate;
}
@Contract("null, _ -> null")
static PsiMethodCallExpression extractMapMethodCall(PsiExpression expression, @NotNull String expectedName) {
expression = PsiUtil.skipParenthesizedExprDown(expression);
if (!(expression instanceof PsiMethodCallExpression)) return null;
PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
if (!expectedName.equals(methodCallExpression.getMethodExpression().getReferenceName())) return null;
final PsiMethod method = methodCallExpression.resolveMethod();
if (method == null) return null;
PsiMethod[] superMethods = method.findDeepestSuperMethods();
if (superMethods.length == 0) {
superMethods = new PsiMethod[]{method};
}
return StreamEx.of(superMethods).map(PsiMember::getContainingClass).nonNull().map(PsiClass::getQualifiedName)
.has(CommonClassNames.JAVA_UTIL_MAP) ? methodCallExpression : null;
}
@Contract("_, null -> null")
@Nullable
private static PsiExpression extractPutValue(MapCheckCondition condition, PsiStatement statement) {
if(!(statement instanceof PsiExpressionStatement)) return null;
PsiMethodCallExpression putCall = extractMapMethodCall(((PsiExpressionStatement)statement).getExpression(), "put");
if (putCall == null) return null;
PsiExpression[] putArguments = putCall.getArgumentList().getExpressions();
return putArguments.length == 2 &&
condition.isMap(putCall.getMethodExpression().getQualifierExpression()) &&
condition.isKey(putArguments[0]) ? putArguments[1] : null;
}
@Nullable
@Contract("_, null -> null")
static PsiMethodCallExpression tryExtractMapGetCall(PsiReferenceExpression target, PsiElement element) {
if(element instanceof PsiDeclarationStatement) {
PsiDeclarationStatement declaration = (PsiDeclarationStatement)element;
PsiElement[] elements = declaration.getDeclaredElements();
if(elements.length > 0) {
PsiElement lastDeclaration = elements[elements.length - 1];
if(lastDeclaration instanceof PsiLocalVariable && target.isReferenceTo(lastDeclaration)) {
PsiLocalVariable var = (PsiLocalVariable)lastDeclaration;
return extractMapMethodCall(var.getInitializer(), "get");
}
}
}
PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(element);
if(assignment != null) {
PsiExpression lValue = assignment.getLExpression();
if (lValue instanceof PsiReferenceExpression &&
EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(target, lValue)) {
return extractMapMethodCall(assignment.getRExpression(), "get");
}
}
return null;
}
@Contract("null, _ -> null")
static MapCheckCondition fromConditional(PsiElement conditional, boolean treatGetNullAsContainsKey) {
if(conditional instanceof PsiIfStatement) {
PsiIfStatement ifStatement = (PsiIfStatement)conditional;
return tryExtract(ifStatement.getCondition(), ifStatement, treatGetNullAsContainsKey);
}
if(conditional instanceof PsiConditionalExpression) {
PsiConditionalExpression ternary = (PsiConditionalExpression)conditional;
PsiElement parent = ternary.getParent().getParent();
return tryExtract(ternary.getCondition(), parent instanceof PsiStatement ? (PsiStatement)parent : null, treatGetNullAsContainsKey);
}
return null;
}
@Nullable
private static MapCheckCondition tryExtract(PsiExpression fullCondition, @Nullable PsiStatement statement, boolean treatGetNullAsContainsKey) {
PsiExpression condition = PsiUtil.skipParenthesizedExprDown(fullCondition);
boolean negated = false;
while(condition != null && BoolUtils.isNegation(condition)) {
negated ^= true;
condition = BoolUtils.getNegated(condition);
}
if(condition == null) return null;
PsiReferenceExpression valueReference = null;
boolean containsKey = false;
PsiMethodCallExpression call;
if(condition instanceof PsiBinaryExpression) {
negated ^= ((PsiBinaryExpression)condition).getOperationTokenType().equals(JavaTokenType.EQEQ);
PsiExpression value = ExpressionUtils.getValueComparedWithNull((PsiBinaryExpression)condition);
if(value instanceof PsiReferenceExpression && statement != null) {
valueReference = (PsiReferenceExpression)value;
PsiElement previous = PsiTreeUtil.skipWhitespacesAndCommentsBackward(statement);
call = tryExtractMapGetCall(valueReference, previous);
} else {
call = extractMapMethodCall(value, "get");
}
} else {
call = extractMapMethodCall(condition, "containsKey");
containsKey = true;
}
if(call == null) return null;
PsiExpression mapExpression = call.getMethodExpression().getQualifierExpression();
if(mapExpression == null) return null;
PsiExpression[] args = call.getArgumentList().getExpressions();
if(args.length != 1) return null;
PsiExpression keyExpression = args[0];
return new MapCheckCondition(valueReference, mapExpression, keyExpression, fullCondition, negated, containsKey,
treatGetNullAsContainsKey);
}
@NotNull
public static String getNameCandidate(String name) {
@@ -373,28 +246,6 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
myResultPointer = manager.createSmartPsiElementPointer(result);
}
@NotNull
static ReplaceWithSingleMapOperation fromIf(String methodName, MapCheckCondition condition, PsiExpression value) {
PsiMethodCallExpression call = condition.getCheckCall();
PsiStatement result = PsiTreeUtil.getParentOfType(call, PsiStatement.class);
LOG.assertTrue(result != null);
return new ReplaceWithSingleMapOperation(methodName, call, value, result);
}
@Nls
@NotNull
@Override
public String getName() {
return QuickFixBundle.message("java.8.map.api.inspection.fix.text", myMethodName);
}
@Nls
@NotNull
@Override
public String getFamilyName() {
return QuickFixBundle.message("java.8.map.api.inspection.fix.family.name");
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement conditional = PsiTreeUtil.getParentOfType(descriptor.getStartElement(), PsiIfStatement.class, PsiConditionalExpression.class);
@@ -477,103 +328,33 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
}
CodeStyleManager.getInstance(project).reformat(result);
}
}
static class MapCheckCondition {
private final @Nullable PsiReferenceExpression myValueReference;
private final PsiExpression myMapExpression;
private final PsiExpression myKeyExpression;
private final PsiExpression myFullCondition;
private final boolean myNegated;
private final boolean myContainsKey;
private final boolean myTreatGetNullAsContainsKey;
private MapCheckCondition(@Nullable PsiReferenceExpression valueReference,
PsiExpression mapExpression,
PsiExpression keyExpression,
PsiExpression fullCondition,
boolean negated,
boolean containsKey,
boolean treatGetNullAsContainsKey) {
myValueReference = valueReference;
myMapExpression = mapExpression;
myKeyExpression = keyExpression;
myFullCondition = fullCondition;
myNegated = negated;
myContainsKey = containsKey;
myTreatGetNullAsContainsKey = treatGetNullAsContainsKey;
@Nls
@NotNull
@Override
public String getName() {
return QuickFixBundle.message("java.8.map.api.inspection.fix.text", myMethodName);
}
boolean isContainsKey() {
return myContainsKey || myTreatGetNullAsContainsKey;
@Nls
@NotNull
@Override
public String getFamilyName() {
return QuickFixBundle.message("java.8.map.api.inspection.fix.family.name");
}
boolean isGetNull() {
return !myContainsKey || myTreatGetNullAsContainsKey;
}
@Contract("null -> false")
boolean isMap(PsiElement element) {
return element != null && PsiEquivalenceUtil.areElementsEquivalent(myMapExpression, element);
}
@Contract("null -> false")
boolean isKey(PsiElement element) {
return element != null && PsiEquivalenceUtil.areElementsEquivalent(myKeyExpression, element);
}
PsiMethodCallExpression extractGetCall(PsiElement element) {
if(!(element instanceof PsiExpression)) return null;
PsiMethodCallExpression getCall = extractMapMethodCall((PsiExpression)element, "get");
if(getCall == null) return null;
PsiExpression[] args = getCall.getArgumentList().getExpressions();
return args.length == 1 && isKey(args[0]) && isMap(getCall.getMethodExpression().getQualifierExpression()) ? getCall : null;
}
@Contract("null -> false")
boolean isValueReference(PsiElement element) {
return element != null && myValueReference != null && PsiEquivalenceUtil.areElementsEquivalent(element, myValueReference);
}
<T extends PsiElement> T getExistsBranch(T thenBranch, T elseBranch) {
return myNegated ? elseBranch : thenBranch;
}
<T extends PsiElement> T getNoneBranch(T thenBranch, T elseBranch) {
return myNegated ? thenBranch : elseBranch;
}
PsiVariable extractDeclaration() {
if(myValueReference == null) return null;
return PsiTreeUtil.getParentOfType(myKeyExpression, PsiVariable.class, true, PsiStatement.class);
}
boolean hasVariable() {
if(myValueReference == null) return false;
PsiVariable var = extractDeclaration();
// has variable, but it used only in condition
return var == null || ReferencesSearch.search(var).findAll().size() != 1;
}
PsiMethodCallExpression getCheckCall() {
return PsiTreeUtil.getParentOfType(myMapExpression, PsiMethodCallExpression.class);
}
public PsiExpression getFullCondition() {
return myFullCondition;
}
public void register(ProblemsHolder holder, boolean informationLevel, ReplaceWithSingleMapOperation fix) {
//noinspection DialogTitleCapitalization
holder.registerProblem(getFullCondition(), QuickFixBundle.message("java.8.map.api.inspection.description", fix.myMethodName),
informationLevel ? ProblemHighlightType.INFORMATION : ProblemHighlightType.GENERIC_ERROR_OR_WARNING, fix);
}
public boolean isMapValueType(@Nullable PsiType type) {
if (type == null) return false;
PsiType mapExpressionType = myMapExpression.getType();
PsiType valueTypeParameter = PsiUtil.substituteTypeParameter(mapExpressionType, CommonClassNames.JAVA_UTIL_MAP, 1, false);
return valueTypeParameter != null && valueTypeParameter.isAssignableFrom(type);
@NotNull
static ReplaceWithSingleMapOperation fromIf(String methodName, MapCheckCondition condition, PsiExpression value) {
PsiMethodCallExpression call = condition.getCheckCall();
PsiStatement result = PsiTreeUtil.getParentOfType(call, PsiStatement.class);
LOG.assertTrue(result != null);
return new ReplaceWithSingleMapOperation(methodName, call, value, result);
}
}
private static void register(MapCheckCondition condition, ProblemsHolder holder, boolean informationLevel, ReplaceWithSingleMapOperation fix) {
holder.registerProblem(condition.getFullCondition(), QuickFixBundle.message("java.8.map.api.inspection.description", fix.getName()),
informationLevel ? ProblemHighlightType.INFORMATION : ProblemHighlightType.GENERIC_ERROR_OR_WARNING, fix);
}
}
@@ -21,7 +21,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.InheritanceUtil;
@@ -29,6 +28,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtil;
import com.siyeh.ig.callMatcher.CallMatcher;
import com.siyeh.ig.psiutils.*;
import com.siyeh.ig.psiutils.ControlFlowUtils.InitializerUsageStatus;
import one.util.streamex.EntryStream;
@@ -46,6 +46,8 @@ import java.util.function.BiFunction;
import static com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.isCallOf;
import static com.intellij.util.ObjectUtils.tryCast;
import static com.siyeh.ig.psiutils.ControlFlowUtils.getInitializerUsageStatus;
import static com.siyeh.ig.psiutils.Java8MigrationUtils.MapCheckCondition.fromConditional;
import static com.siyeh.ig.psiutils.Java8MigrationUtils.extractLambdaCandidate;
/**
* @author Tagir Valeev
@@ -135,7 +137,7 @@ class CollectMigration extends BaseStreamApiMigration {
if (tb.dependsOn(qualifierExpression)) return null;
List<BiFunction<TerminalBlock, PsiMethodCallExpression, CollectTerminal>> extractors = Arrays
.asList(AddingTerminal::tryExtract, ToMapTerminal::tryExtract, AddingAllTerminal::tryExtractAddAll);
.asList(AddingTerminal::tryExtract, GroupingTerminal::tryExtractJava8Style, ToMapTerminal::tryExtract, AddingAllTerminal::tryExtractAddAll);
CollectTerminal terminal = StreamEx.of(extractors).map(extractor -> extractor.apply(tb, call)).nonNull().findFirst().orElse(null);
if (terminal != null) {
@@ -387,13 +389,17 @@ class CollectMigration extends BaseStreamApiMigration {
}
static class GroupingTerminal extends CollectTerminal {
private final static CallMatcher LIST_ADD = CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_LIST, "add").parameterCount(1);
private final static CallMatcher COMPUTE_IF_ABSENT = CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_MAP, "computeIfAbsent").parameterCount(2);
private final AddingTerminal myDownstream;
private final PsiExpression myKeyExpression;
GroupingTerminal(AddingTerminal downstream,
PsiLocalVariable target,
PsiExpression expression,
InitializerUsageStatus status) {
GroupingTerminal(@NotNull AddingTerminal downstream,
@NotNull PsiLocalVariable target,
@NotNull PsiExpression expression,
@NotNull InitializerUsageStatus status) {
super(target, downstream.myLoop, status);
myDownstream = downstream;
myKeyExpression = expression;
@@ -432,9 +438,13 @@ class CollectMigration extends BaseStreamApiMigration {
static GroupingTerminal tryExtract(@NotNull TerminalBlock tb, @Nullable List<PsiVariable> nonFinalVariables) {
PsiStatement[] statements = tb.getStatements();
if (statements.length == 1) {
if(nonFinalVariables != null && nonFinalVariables.isEmpty()) return null;
if(nonFinalVariables != null && !nonFinalVariables.isEmpty()) return null;
PsiMethodCallExpression call = tb.getSingleExpression(PsiMethodCallExpression.class);
return tryExtract(tb, call);
return tryExtractJava8Style(tb, call);
}
if (statements.length == 2) {
if(nonFinalVariables != null && !nonFinalVariables.isEmpty()) return null;
return tryExtractWithIntermediateVariable(tb);
}
return tryExtractJava7Style(tb, statements, nonFinalVariables);
}
@@ -453,127 +463,103 @@ class CollectMigration extends BaseStreamApiMigration {
@Nullable List<PsiVariable> nonFinalVariables) {
if(nonFinalVariables != null && nonFinalVariables.size() != 1) return null;
if (statements.length != 3) return null;
PsiDeclarationStatement declaration = tryCast(statements[0], PsiDeclarationStatement.class);
PsiIfStatement ifStatement = tryCast(statements[1], PsiIfStatement.class);
if(ifStatement == null) return null;
Java8MigrationUtils.MapCheckCondition condition = fromConditional(ifStatement, false);
if(condition == null || !condition.hasVariable()) return null;
PsiStatement existsBranch = ControlFlowUtils.stripBraces(condition.getExistsBranch(ifStatement.getThenBranch(), ifStatement.getElseBranch()));
PsiStatement noneBranch = ControlFlowUtils.stripBraces(condition.getNoneBranch(ifStatement.getThenBranch(), ifStatement.getElseBranch()));
if(existsBranch != null) return null;
PsiExpression lambdaCandidate = extractLambdaCandidate(condition, noneBranch);
if(lambdaCandidate == null) return null;
PsiExpressionStatement additionToListStatement = tryCast(statements[2], PsiExpressionStatement.class);
if (declaration == null || ifStatement == null || additionToListStatement == null) return null;
PsiElement[] declaredElements = declaration.getDeclaredElements();
if (declaredElements.length != 1) return null;
if (additionToListStatement == null) return null;
PsiLocalVariable target = tryCast(declaredElements[0], PsiLocalVariable.class);
if (target == null) return null;
if(nonFinalVariables != null && !target.equals(nonFinalVariables.get(0))) return null;
if (!InheritanceUtil.isInheritor(target.getType(), CommonClassNames.JAVA_UTIL_LIST)) return null;
PsiExpression initializer = target.getInitializer();
PsiMethodCallExpression getCall = tryCast(initializer, PsiMethodCallExpression.class);
if (!isCallOf(getCall, CommonClassNames.JAVA_UTIL_MAP, "get")) return null;
PsiExpression[] expressions = getCall.getArgumentList().getExpressions();
if (expressions.length != 1) return null;
PsiExpression keyExtractor = expressions[0];
PsiReferenceExpression mapReference =
tryCast(getCall.getMethodExpression().getQualifierExpression(), PsiReferenceExpression.class);
if (mapReference == null) return null;
PsiLocalVariable mapVariable = tryCast(mapReference.resolve(), PsiLocalVariable.class);
if (!isValidIf(ifStatement, target, keyExtractor, mapVariable)) return null;
PsiReferenceExpression valueReference = condition.getValueReference();
if(valueReference == null) return null;
PsiLocalVariable listVar = tryCast(valueReference.resolve(), PsiLocalVariable.class);
if (nonFinalVariables != null && !nonFinalVariables.get(0).equals(listVar) ||
listVar == null ||
!InheritanceUtil.isInheritor(listVar.getType(), CommonClassNames.JAVA_UTIL_LIST)) {
return null;
}
PsiLocalVariable mapVariable = ExpressionUtils.resolveLocalVariable(condition.getMapExpression());
if(mapVariable == null) return null;
PsiMethodCallExpression addCall = extractAddMethod(terminalBlock, additionToListStatement);
if(addCall == null) return null;
PsiType type = target.getType();
PsiClassReferenceType referenceType = tryCast(type, PsiClassReferenceType.class);
if(referenceType == null) return null;
PsiType[] parameters = referenceType.getParameters();
if(parameters.length != 1) return null;
PsiType typeParameter = parameters[0];
InitializerUsageStatus status = getInitializerUsageStatus(terminalBlock.getVariable(), terminalBlock.getMainLoop());
PsiElementFactory factory = JavaPsiFacade.getElementFactory(terminalBlock.getMainLoop().getProject());
PsiExpression text = factory.createExpressionFromText("new ArrayList<String>()", additionToListStatement);
AddingTerminal adding = new AddingTerminal(typeParameter, text, terminalBlock.getVariable(), addCall);
return new GroupingTerminal(adding, mapVariable, keyExtractor, status);
InitializerUsageStatus status = getInitializerUsageStatus(mapVariable, terminalBlock.getStreamSourceStatement());
AddingTerminal adding = new AddingTerminal(listVar.getType(), lambdaCandidate, terminalBlock.getVariable(), addCall);
return new GroupingTerminal(adding, mapVariable, condition.getKeyExpression(), status);
}
private static PsiMethodCallExpression extractAddMethod(@NotNull TerminalBlock terminalBlock, PsiExpressionStatement additionToListStatement) {
@Nullable
private static PsiMethodCallExpression extractAddMethod(@NotNull TerminalBlock terminalBlock,
@NotNull PsiExpressionStatement additionToListStatement) {
PsiMethodCallExpression additionToList = tryCast(additionToListStatement.getExpression(), PsiMethodCallExpression.class);
if (!isCallOf(additionToList, CommonClassNames.JAVA_UTIL_LIST, "add")) return null;
if (!LIST_ADD.test(additionToList)) return null;
PsiExpression[] additionArgs = additionToList.getArgumentList().getExpressions();
if (additionArgs.length != 1) return null;
PsiExpression arg = additionArgs[0];
PsiReferenceExpression referenceExpression = tryCast(arg, PsiReferenceExpression.class);
if (referenceExpression == null) return null;
PsiVariable savedVar = tryCast(referenceExpression.resolve(), PsiVariable.class);
if(savedVar == null) return null;
if (!savedVar.equals(terminalBlock.getVariable())) return null;
return additionToList;
}
private static boolean isValidIf(PsiIfStatement ifStatement,
PsiLocalVariable variable,
PsiExpression keyExtractor,
PsiVariable getMapVar) {
if (ifStatement.getElseBranch() != null) return false;
PsiExpression condition = ifStatement.getCondition();
if (condition == null) return false;
PsiVariable nullChecked = ExpressionUtils.getVariableFromNullComparison(condition, true);
if (!variable.equals(nullChecked)) return false;
PsiBlockStatement blockStatement = tryCast(ifStatement.getThenBranch(), PsiBlockStatement.class);
if (blockStatement == null) return false;
PsiStatement[] ifStatements = blockStatement.getCodeBlock().getStatements();
if (ifStatements.length != 2) return false;
@Nullable
public static GroupingTerminal tryExtractJava8Style(@NotNull TerminalBlock tb, @Nullable PsiMethodCallExpression call) {
if(call == null) return null;
PsiExpression qualifier = call.getMethodExpression().getQualifierExpression();
return tryExtractJava8Style(tb, tryCast(qualifier, PsiMethodCallExpression.class), tryCast(call, PsiMethodCallExpression.class));
}
PsiExpression assignment = ExpressionUtils.getAssignmentTo(ifStatements[0], variable);
PsiNewExpression newExpression = tryCast(assignment, PsiNewExpression.class);
if (newExpression == null) return false;
PsiJavaCodeReferenceElement reference = newExpression.getClassReference();
if (reference == null) return false;
PsiClass aClass = tryCast(reference.resolve(), PsiClass.class);
if (!CommonClassNames.JAVA_UTIL_ARRAY_LIST.equals(aClass.getQualifiedName())) return false;
/*
Map<Integer, List<String>> map = new HashMap<>();
for (String s : list) {
List<String> strings = map.computeIfAbsent(s.length(), k -> new ArrayList<>());
strings.add(s);
}
*/
@Nullable
private static GroupingTerminal tryExtractWithIntermediateVariable(@NotNull TerminalBlock terminalBlock) {
PsiStatement[] statements = terminalBlock.getStatements();
PsiDeclarationStatement assignmentStmt = tryCast(statements[0], PsiDeclarationStatement.class);
if(assignmentStmt == null) return null;
PsiElement[] elements = assignmentStmt.getDeclaredElements();
if(elements.length != 1) return null;
PsiLocalVariable variable = tryCast(elements[0], PsiLocalVariable.class);
if(variable == null) return null;
PsiExpressionStatement mapPutStatement = tryCast(ifStatements[1], PsiExpressionStatement.class);
if (mapPutStatement == null) return false;
PsiMethodCallExpression mapPut = tryCast(mapPutStatement.getExpression(), PsiMethodCallExpression.class);
if (!isCallOf(mapPut, CommonClassNames.JAVA_UTIL_MAP, "put")) return false;
PsiExpressionStatement addStmt = tryCast(statements[1], PsiExpressionStatement.class);
if(addStmt == null) return null;
PsiMethodCallExpression maybeAddCall = tryCast(addStmt.getExpression(), PsiMethodCallExpression.class);
if(maybeAddCall == null) return null;
PsiExpression qualifier = maybeAddCall.getMethodExpression().getQualifierExpression();
if(!ExpressionUtils.isReferenceTo(qualifier, variable)) return null;
PsiReferenceExpression mapPutQualifierReference =
tryCast(mapPut.getMethodExpression().getQualifierExpression(), PsiReferenceExpression.class);
if(mapPutQualifierReference == null) return false;
PsiVariable putMapVar = tryCast(mapPutQualifierReference.resolve(), PsiVariable.class);
if(putMapVar == null) return false;
if (!putMapVar.equals(getMapVar)) return false;
PsiExpression[] mapPutArgs = mapPut.getArgumentList().getExpressions();
if (mapPutArgs.length != 2) return false;
PsiExpression putKeyExtractor = mapPutArgs[0];
if (!EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(putKeyExtractor, keyExtractor)) return false;
PsiReferenceExpression referenceExpression = tryCast(mapPutArgs[1], PsiReferenceExpression.class);
if (referenceExpression == null) return false;
PsiVariable savingVar = tryCast(referenceExpression.resolve(), PsiVariable.class);
if (!variable.equals(savingVar)) return false;
return true;
return tryExtractJava8Style(terminalBlock, tryCast(variable.getInitializer(), PsiMethodCallExpression.class), maybeAddCall);
}
@Nullable
public static GroupingTerminal tryExtract(@NotNull TerminalBlock tb, @Nullable PsiMethodCallExpression call) {
if (!isCallOf(call, CommonClassNames.JAVA_UTIL_COLLECTION, "add")) return null;
PsiReferenceExpression methodExpression = call.getMethodExpression();
PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
if (qualifierExpression instanceof PsiMethodCallExpression && tb.getCountExpression() == null) {
PsiMethodCallExpression qualifierCall = (PsiMethodCallExpression)qualifierExpression;
if (isCallOf(qualifierCall, CommonClassNames.JAVA_UTIL_MAP, "computeIfAbsent")) {
PsiExpression[] args = qualifierCall.getArgumentList().getExpressions();
if (args.length != 2 || !(args[1] instanceof PsiLambdaExpression)) return null;
PsiLambdaExpression lambda = (PsiLambdaExpression)args[1];
PsiExpression body = LambdaUtil.extractSingleExpressionFromBody(lambda.getBody());
if (ConstructionUtils.isEmptyCollectionInitializer(body)) {
PsiLocalVariable variable = extractQualifierVariable(tb, qualifierCall);
if (hasLambdaCompatibleEmptyInitializer(variable)) {
PsiType mapType = variable.getType();
PsiType valueType = PsiUtil.substituteTypeParameter(mapType, CommonClassNames.JAVA_UTIL_MAP, 1, false);
if (valueType == null) return null;
AddingTerminal adding = new AddingTerminal(valueType, body, tb.getVariable(), call);
InitializerUsageStatus status = getInitializerUsageStatus(variable, tb.getStreamSourceStatement());
return new GroupingTerminal(adding, variable, args[0], status);
}
}
public static GroupingTerminal tryExtractJava8Style(@NotNull TerminalBlock tb,
@Nullable PsiMethodCallExpression computeIfAbsentCall,
@Nullable PsiMethodCallExpression addCall) {
if (!LIST_ADD.test(addCall) || !COMPUTE_IF_ABSENT.test(computeIfAbsentCall)) return null;
PsiExpression[] args = computeIfAbsentCall.getArgumentList().getExpressions();
if (args.length != 2 || !(args[1] instanceof PsiLambdaExpression)) return null;
PsiLambdaExpression lambda = (PsiLambdaExpression)args[1];
PsiExpression body = LambdaUtil.extractSingleExpressionFromBody(lambda.getBody());
if (ConstructionUtils.isEmptyCollectionInitializer(body)) {
PsiLocalVariable variable = extractQualifierVariable(tb, computeIfAbsentCall);
if (hasLambdaCompatibleEmptyInitializer(variable)) {
PsiType mapType = variable.getType();
PsiType valueType = PsiUtil.substituteTypeParameter(mapType, CommonClassNames.JAVA_UTIL_MAP, 1, false);
if (valueType == null) return null;
AddingTerminal adding = new AddingTerminal(valueType, body, tb.getVariable(), addCall);
InitializerUsageStatus status = getInitializerUsageStatus(variable, tb.getStreamSourceStatement());
return new GroupingTerminal(adding, variable, args[0], status);
}
}
return null;
@@ -644,7 +630,6 @@ class CollectMigration extends BaseStreamApiMigration {
return new ToMapTerminal(call, tb.getVariable(), variable, tb.getStreamSourceStatement(), status);
}
}
static class SortingTerminal extends CollectTerminal {
private final CollectTerminal myDownstream;
private final PsiExpression myComparator;
@@ -480,19 +480,17 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
if (isCountOperation(nonFinalVariables, tb)) {
return new CountMigration(true);
}
if (nonFinalVariables.size() == 0) {
CollectMigration.CollectTerminal terminal = CollectMigration.extractCollectTerminal(tb, nonFinalVariables);
if (terminal != null) {
boolean addAll = loop instanceof PsiForeachStatement && !tb.hasOperations() && isAddAllCall(tb);
// Don't suggest to convert the loop which can be trivially replaced via addAll:
// this is covered by UseBulkOperationInspection and ManualArrayToCollectionCopyInspection
if (addAll) return null;
boolean shouldWarn = replaceTrivialForEach ||
tb.hasOperations() ||
tb.getLastOperation() instanceof BufferedReaderLines ||
!terminal.isTrivial();
return new CollectMigration(shouldWarn, terminal.getMethodName());
}
CollectMigration.CollectTerminal terminal = CollectMigration.extractCollectTerminal(tb, nonFinalVariables);
if (terminal != null) {
boolean addAll = loop instanceof PsiForeachStatement && !tb.hasOperations() && isAddAllCall(tb);
// Don't suggest to convert the loop which can be trivially replaced via addAll:
// this is covered by UseBulkOperationInspection and ManualArrayToCollectionCopyInspection
if (addAll) return null;
boolean shouldWarn = replaceTrivialForEach ||
tb.hasOperations() ||
tb.getLastOperation() instanceof BufferedReaderLines ||
!terminal.isTrivial();
return new CollectMigration(shouldWarn, terminal.getMethodName());
}
if(JoiningMigration.extractTerminal(tb, nonFinalVariables) != null) {
return new JoiningMigration(true);
@@ -0,0 +1,14 @@
// "Replace with collect" "true"
import java.util.*;
import java.util.stream.Collectors;
public class Main {
private Map<Integer, List<String>> test(String... list) {
Map<Integer, List<String>> map = Arrays.stream(list).filter(Objects::nonNull).collect(Collectors.groupingBy(String::length));
return map;
}
public static void main(String[] args) {
System.out.println(new Main().test("a", "bbb", null, "cc", "dd", "eedasfasdfs", "dd"));
}
}
@@ -4,9 +4,8 @@ import java.util.stream.Collectors;
public class Main {
private Map<Integer, List<String>> test(String... list) {
Map<Integer, List<String>> map = new HashMap<>();
map = Arrays.stream(list).filter(Objects::nonNull).collect(Collectors.groupingBy(String::length, Collectors.toCollection(ArrayList::new)));
return map;
Map<Integer, List<String>> map = Arrays.stream(list).filter(Objects::nonNull).collect(Collectors.groupingBy(String::length));
return map;
}
public static void main(String[] args) {
@@ -0,0 +1,14 @@
// "Replace with collect" "true"
import java.util.*;
import java.util.stream.Collectors;
public class Main {
Map<Integer, List<String>> test(List<String> list) {
Map<Integer, List<String>> map = list.stream().collect(Collectors.groupingBy(String::length));
return map;
}
public static void main(String[] args) {
System.out.println(new Main().test("a", "bbb", null, "cc", "dd", "eedasfasdfs", "dd"));
}
}
@@ -0,0 +1,20 @@
// "Replace with collect" "true"
import java.util.*;
public class Main {
private Map<Integer, List<String>> test(String... list) {
Map<Integer, List<String>> map = new HashMap<>();
for(String s : li<caret>st) {
if(s != null) {
List<String> tmp = map.get(s.length());
if(tmp == null) map.put(s.length(), tmp = new ArrayList<>());
tmp.add(s);
}
}
return map;
}
public static void main(String[] args) {
System.out.println(new Main().test("a", "bbb", null, "cc", "dd", "eedasfasdfs", "dd"));
}
}
@@ -0,0 +1,17 @@
// "Replace with collect" "true"
import java.util.*;
public class Main {
Map<Integer, List<String>> test(List<String> list) {
Map<Integer, List<String>> map = new HashMap<>();
for<caret> (String s : list) {
List<String> strings = map.computeIfAbsent(s.length(), k -> new ArrayList<>());
strings.add(s);
}
return map;
}
public static void main(String[] args) {
System.out.println(new Main().test("a", "bbb", null, "cc", "dd", "eedasfasdfs", "dd"));
}
}
@@ -0,0 +1,294 @@
/*
* Copyright 2000-2017 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.siyeh.ig.psiutils;
import com.intellij.codeInsight.PsiEquivalenceUtil;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.codeInspection.util.LambdaGenerationUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class Java8MigrationUtils {
@Nullable
private static Java8MigrationUtils.MapCheckCondition tryExtract(PsiExpression fullCondition,
@Nullable PsiStatement statement,
boolean treatGetNullAsContainsKey) {
PsiExpression condition = PsiUtil.skipParenthesizedExprDown(fullCondition);
boolean negated = false;
while (condition != null && BoolUtils.isNegation(condition)) {
negated ^= true;
condition = BoolUtils.getNegated(condition);
}
if (condition == null) return null;
PsiReferenceExpression valueReference = null;
boolean containsKey = false;
PsiMethodCallExpression call;
if (condition instanceof PsiBinaryExpression) {
negated ^= ((PsiBinaryExpression)condition).getOperationTokenType().equals(JavaTokenType.EQEQ);
PsiExpression value = ExpressionUtils.getValueComparedWithNull((PsiBinaryExpression)condition);
if (value instanceof PsiReferenceExpression && statement != null) {
valueReference = (PsiReferenceExpression)value;
PsiElement previous = PsiTreeUtil.skipWhitespacesAndCommentsBackward(statement);
call = tryExtractMapGetCall(valueReference, previous);
}
else {
call = extractMapMethodCall(value, "get");
}
}
else {
call = extractMapMethodCall(condition, "containsKey");
containsKey = true;
}
if (call == null) return null;
PsiExpression mapExpression = call.getMethodExpression().getQualifierExpression();
if (mapExpression == null) return null;
PsiExpression[] args = call.getArgumentList().getExpressions();
if (args.length != 1) return null;
PsiExpression keyExpression = args[0];
return new Java8MigrationUtils.MapCheckCondition(valueReference, mapExpression, keyExpression, fullCondition, negated, containsKey,
treatGetNullAsContainsKey);
}
@Nullable
@Contract("_, null -> null")
private static PsiMethodCallExpression tryExtractMapGetCall(PsiReferenceExpression target, PsiElement element) {
if (element instanceof PsiDeclarationStatement) {
PsiDeclarationStatement declaration = (PsiDeclarationStatement)element;
PsiElement[] elements = declaration.getDeclaredElements();
if (elements.length > 0) {
PsiElement lastDeclaration = elements[elements.length - 1];
if (lastDeclaration instanceof PsiLocalVariable && target.isReferenceTo(lastDeclaration)) {
PsiLocalVariable var = (PsiLocalVariable)lastDeclaration;
return extractMapMethodCall(var.getInitializer(), "get");
}
}
}
PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(element);
if (assignment != null) {
PsiExpression lValue = assignment.getLExpression();
if (lValue instanceof PsiReferenceExpression &&
EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(target, lValue)) {
return extractMapMethodCall(assignment.getRExpression(), "get");
}
}
return null;
}
/**
* extracts the call of the Map class
* @param expression expected to be {@link PsiMethodCallExpression}
* @param expectedName name of the Map method
*/
@Contract("null, _ -> null")
public static PsiMethodCallExpression extractMapMethodCall(PsiExpression expression, @NotNull String expectedName) {
expression = PsiUtil.skipParenthesizedExprDown(expression);
if (!(expression instanceof PsiMethodCallExpression)) return null;
PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
if (!expectedName.equals(methodCallExpression.getMethodExpression().getReferenceName())) return null;
final PsiMethod method = methodCallExpression.resolveMethod();
if (method == null) return null;
PsiMethod[] superMethods = method.findDeepestSuperMethods();
if (superMethods.length == 0) {
superMethods = new PsiMethod[]{method};
}
return StreamEx.of(superMethods).map(PsiMember::getContainingClass).nonNull().map(PsiClass::getQualifiedName)
.has(CommonClassNames.JAVA_UTIL_MAP) ? methodCallExpression : null;
}
/**
* Extracts expression, that can be lambda body from Map.put() call
* @param statement - put call or block with expected put call inside
*/
@Nullable
public static PsiExpression extractLambdaCandidate(Java8MigrationUtils.MapCheckCondition condition, PsiStatement statement) {
PsiAssignmentExpression assignment;
PsiExpression putValue = extractPutValue(condition, statement);
if (putValue != null) {
// like map.put(key, val = new ArrayList<>());
assignment = ExpressionUtils.getAssignment(putValue);
}
else {
if (!(statement instanceof PsiBlockStatement)) return null;
// like val = new ArrayList<>(); map.put(key, val);
PsiStatement[] statements = ((PsiBlockStatement)statement).getCodeBlock().getStatements();
if (statements.length != 2) return null;
putValue = extractPutValue(condition, statements[1]);
if (!condition.isValueReference(putValue)) return null;
assignment = ExpressionUtils.getAssignment(statements[0]);
}
if (assignment == null) return null;
PsiExpression lambdaCandidate = assignment.getRExpression();
if (lambdaCandidate == null || !condition.isValueReference(assignment.getLExpression())) return null;
if (!LambdaGenerationUtil.canBeUncheckedLambda(lambdaCandidate)) return null;
return lambdaCandidate;
}
/**
* @return put value
*/
@Contract("_, null -> null")
@Nullable
public static PsiExpression extractPutValue(Java8MigrationUtils.MapCheckCondition condition, PsiStatement statement) {
if (!(statement instanceof PsiExpressionStatement)) return null;
PsiMethodCallExpression putCall = extractMapMethodCall(((PsiExpressionStatement)statement).getExpression(), "put");
if (putCall == null) return null;
PsiExpression[] putArguments = putCall.getArgumentList().getExpressions();
return putArguments.length == 2 &&
condition.isMap(putCall.getMethodExpression().getQualifierExpression()) &&
condition.isKey(putArguments[0]) ? putArguments[1] : null;
}
/**
* Class represents check when working with map: there is 2 ways - when there is a value that matches the key, and when value doesn't exists
*/
public static class MapCheckCondition {
private final @Nullable PsiReferenceExpression myValueReference;
private final PsiExpression myMapExpression;
private final PsiExpression myKeyExpression;
private final PsiExpression myFullCondition;
private final boolean myNegated;
private final boolean myContainsKey;
private final boolean myTreatGetNullAsContainsKey;
private MapCheckCondition(@Nullable PsiReferenceExpression valueReference,
PsiExpression mapExpression,
PsiExpression keyExpression,
PsiExpression fullCondition,
boolean negated,
boolean containsKey,
boolean treatGetNullAsContainsKey) {
myValueReference = valueReference;
myMapExpression = mapExpression;
myKeyExpression = keyExpression;
myFullCondition = fullCondition;
myNegated = negated;
myContainsKey = containsKey;
myTreatGetNullAsContainsKey = treatGetNullAsContainsKey;
}
@Nullable
public PsiReferenceExpression getValueReference() {
return myValueReference;
}
@Nullable
public PsiExpression getMapExpression() {
return myMapExpression;
}
public PsiExpression getKeyExpression() {
return myKeyExpression;
}
public boolean isContainsKey() {
return myContainsKey || myTreatGetNullAsContainsKey;
}
public boolean isGetNull() {
return !myContainsKey || myTreatGetNullAsContainsKey;
}
@Contract("null -> false")
public boolean isMap(PsiElement element) {
return element != null && PsiEquivalenceUtil.areElementsEquivalent(myMapExpression, element);
}
@Contract("null -> false")
public boolean isKey(PsiElement element) {
return element != null && PsiEquivalenceUtil.areElementsEquivalent(myKeyExpression, element);
}
public PsiMethodCallExpression extractGetCall(PsiElement element) {
if (!(element instanceof PsiExpression)) return null;
PsiMethodCallExpression getCall = extractMapMethodCall((PsiExpression)element, "get");
if (getCall == null) return null;
PsiExpression[] args = getCall.getArgumentList().getExpressions();
return args.length == 1 && isKey(args[0]) && isMap(getCall.getMethodExpression().getQualifierExpression()) ? getCall : null;
}
@Contract("null -> false")
public boolean isValueReference(PsiElement element) {
return element != null && myValueReference != null && PsiEquivalenceUtil.areElementsEquivalent(element, myValueReference);
}
public <T extends PsiElement> T getExistsBranch(T thenBranch, T elseBranch) {
return myNegated ? elseBranch : thenBranch;
}
public <T extends PsiElement> T getNoneBranch(T thenBranch, T elseBranch) {
return myNegated ? thenBranch : elseBranch;
}
public PsiVariable extractDeclaration() {
if (myValueReference == null) return null;
return PsiTreeUtil.getParentOfType(myKeyExpression, PsiVariable.class, true, PsiStatement.class);
}
public boolean hasVariable() {
if (myValueReference == null) return false;
PsiVariable var = extractDeclaration();
// has variable, but it used only in condition
return var == null || ReferencesSearch.search(var).findAll().size() != 1;
}
public PsiMethodCallExpression getCheckCall() {
return PsiTreeUtil.getParentOfType(myMapExpression, PsiMethodCallExpression.class);
}
public PsiExpression getFullCondition() {
return myFullCondition;
}
public void register(ProblemsHolder holder, boolean informationLevel, LocalQuickFix fix, String methodName) {
//noinspection DialogTitleCapitalization
holder.registerProblem(getFullCondition(), QuickFixBundle.message("java.8.map.api.inspection.description", methodName),
informationLevel ? ProblemHighlightType.INFORMATION : ProblemHighlightType.GENERIC_ERROR_OR_WARNING, fix);
}
public boolean isMapValueType(@Nullable PsiType type) {
if (type == null) return false;
PsiType mapExpressionType = myMapExpression.getType();
PsiType valueTypeParameter = PsiUtil.substituteTypeParameter(mapExpressionType, CommonClassNames.JAVA_UTIL_MAP, 1, false);
return valueTypeParameter != null && valueTypeParameter.isAssignableFrom(type);
}
@Contract("null, _ -> null")
public static Java8MigrationUtils.MapCheckCondition fromConditional(PsiElement conditional, boolean treatGetNullAsContainsKey) {
if (conditional instanceof PsiIfStatement) {
PsiIfStatement ifStatement = (PsiIfStatement)conditional;
return tryExtract(ifStatement.getCondition(), ifStatement, treatGetNullAsContainsKey);
}
if (conditional instanceof PsiConditionalExpression) {
PsiConditionalExpression ternary = (PsiConditionalExpression)conditional;
PsiElement parent = ternary.getParent().getParent();
return tryExtract(ternary.getCondition(), parent instanceof PsiStatement ? (PsiStatement)parent : null, treatGetNullAsContainsKey);
}
return null;
}
}
}