mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
"push condition inside call" intention replaced with "Conditional can be pushed inside branch" inspection
This commit is contained in:
@@ -1,184 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.codeInsight.intention.impl;
|
||||
|
||||
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
||||
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PushConditionInCallAction extends PsiElementBaseIntentionAction {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return "Push condition inside call";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
|
||||
|
||||
if (element instanceof PsiCompiledElement) return false;
|
||||
if (!element.getManager().isInProject(element)) return false;
|
||||
|
||||
// if (!(element instanceof PsiJavaToken && ((PsiJavaToken)element).getTokenType() == JavaTokenType.QUEST)) return false;
|
||||
final PsiConditionalExpression conditionalExpression = PsiTreeUtil.getParentOfType(element, PsiConditionalExpression.class);
|
||||
if (conditionalExpression == null) return false;
|
||||
final String conditionText = conditionalExpression.getCondition().getText();
|
||||
final PsiExpression thenExpression = conditionalExpression.getThenExpression();
|
||||
final PsiExpression elseExpression = conditionalExpression.getElseExpression();
|
||||
|
||||
return isAvailable(conditionText, thenExpression, elseExpression, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
|
||||
final PsiConditionalExpression conditionalExpression = PsiTreeUtil.getParentOfType(element, PsiConditionalExpression.class);
|
||||
if (conditionalExpression == null) return;
|
||||
PsiExpression thenExpression = conditionalExpression.getThenExpression();
|
||||
if (thenExpression == null) return;
|
||||
|
||||
thenExpression = (PsiExpression)thenExpression.copy();
|
||||
replaceRecursively(project, conditionalExpression, thenExpression, conditionalExpression.getElseExpression());
|
||||
CodeStyleManager.getInstance(project).reformat(conditionalExpression.replace(thenExpression));
|
||||
}
|
||||
|
||||
private boolean isAvailable(String conditionText, PsiExpression thenExpression, PsiExpression elseExpression, int level) {
|
||||
if (!(thenExpression instanceof PsiCallExpression)) return false;
|
||||
final PsiMethod thenMethod = ((PsiCallExpression)thenExpression).resolveMethod();
|
||||
final PsiExpressionList thenArgsList = ((PsiCallExpression)thenExpression).getArgumentList();
|
||||
if (thenArgsList == null) return false;
|
||||
final PsiExpression[] thenExpressions = thenArgsList.getExpressions();
|
||||
|
||||
if (!(elseExpression instanceof PsiCallExpression)) return false;
|
||||
final PsiMethod elseMethod = ((PsiCallExpression)elseExpression).resolveMethod();
|
||||
final PsiExpressionList elseArgsList = ((PsiCallExpression)elseExpression).getArgumentList();
|
||||
if (elseArgsList == null) return false;
|
||||
final PsiExpression[] elseExpressions = elseArgsList.getExpressions();
|
||||
|
||||
if (thenMethod != elseMethod || thenMethod == null) return false;
|
||||
|
||||
if (thenExpressions.length != elseExpressions.length) return false;
|
||||
|
||||
final Pair<PsiExpression, PsiExpression> qualifiers = getQualifiers(thenExpression, elseExpression);
|
||||
if (qualifiers != null) {
|
||||
if (!isSameCall(thenExpressions, elseExpressions) && level == 0){
|
||||
return false;
|
||||
}
|
||||
if (level > 0) {
|
||||
setText("Push condition '" + conditionText + "' inside " + (thenMethod.isConstructor() ? "constructor" : "method") + " call");
|
||||
return true;
|
||||
}
|
||||
return level > 0 || isAvailable(conditionText, qualifiers.first, qualifiers.second, level + 1);
|
||||
}
|
||||
|
||||
PsiExpression tExpr = null;
|
||||
for (int i = 0; i < thenExpressions.length; i++) {
|
||||
PsiExpression lExpr = thenExpressions[i];
|
||||
PsiExpression rExpr = elseExpressions[i];
|
||||
if (!PsiEquivalenceUtil.areElementsEquivalent(lExpr, rExpr)) {
|
||||
if (tExpr == null) {
|
||||
tExpr = lExpr;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
setText("Push condition '" + conditionText + "' inside " + (thenMethod.isConstructor() ? "constructor" : "method") + " call");
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isSameCall(PsiExpression[] thenExpressions, PsiExpression[] elseExpressions) {
|
||||
for (int i = 0; i < thenExpressions.length; i++) {
|
||||
final PsiExpression lExpr = thenExpressions[i];
|
||||
final PsiExpression rExpr = elseExpressions[i];
|
||||
if (!PsiEquivalenceUtil.areElementsEquivalent(lExpr, rExpr)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Pair<PsiExpression, PsiExpression> getQualifiers(PsiExpression thenExpression, PsiExpression elseExpression) {
|
||||
PsiExpression thenQualifier = null;
|
||||
PsiExpression elseQualifier = null;
|
||||
if (thenExpression instanceof PsiMethodCallExpression && elseExpression instanceof PsiMethodCallExpression) {
|
||||
thenQualifier = ((PsiMethodCallExpression)thenExpression).getMethodExpression().getQualifierExpression();
|
||||
elseQualifier = ((PsiMethodCallExpression)elseExpression).getMethodExpression().getQualifierExpression();
|
||||
}
|
||||
else if (thenExpression instanceof PsiNewExpression && elseExpression instanceof PsiNewExpression) {
|
||||
thenQualifier = ((PsiNewExpression)thenExpression).getQualifier();
|
||||
elseQualifier = ((PsiNewExpression)elseExpression).getQualifier();
|
||||
}
|
||||
|
||||
if (thenQualifier == null ^ elseQualifier == null ||
|
||||
thenQualifier != null && !PsiEquivalenceUtil.areElementsEquivalent(thenQualifier, elseQualifier)) {
|
||||
return Pair.create(thenQualifier, elseQualifier);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void replaceRecursively(@NotNull Project project,
|
||||
PsiConditionalExpression conditionalExpression,
|
||||
PsiExpression thenExpression,
|
||||
PsiExpression elseExpression) {
|
||||
final PsiExpressionList thenArgsList = ((PsiCallExpression)thenExpression).getArgumentList();
|
||||
if (thenArgsList == null) return;
|
||||
final PsiExpression[] thenExpressions = thenArgsList.getExpressions();
|
||||
|
||||
final PsiExpressionList elseArgsList = ((PsiCallExpression)elseExpression).getArgumentList();
|
||||
if (elseArgsList == null) return;
|
||||
final PsiExpression[] elseExpressions = elseArgsList.getExpressions();
|
||||
|
||||
final Pair<PsiExpression, PsiExpression> qualifiers = getQualifiers(thenExpression, elseExpression);
|
||||
if (qualifiers != null) {
|
||||
if (isSameCall(thenExpressions, elseExpressions)) {
|
||||
replaceRecursively(project, conditionalExpression, qualifiers.first, qualifiers.second);
|
||||
}
|
||||
else {
|
||||
pushConditional(project, conditionalExpression, thenExpression, elseExpression);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < thenExpressions.length; i++) {
|
||||
PsiExpression lExpr = thenExpressions[i];
|
||||
PsiExpression rExpr = elseExpressions[i];
|
||||
if (pushConditional(project, conditionalExpression, lExpr, rExpr)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean pushConditional(@NotNull Project project,
|
||||
PsiConditionalExpression conditionalExpression,
|
||||
PsiExpression thenExpression,
|
||||
PsiExpression elseExpression) {
|
||||
if (!PsiEquivalenceUtil.areElementsEquivalent(thenExpression, elseExpression)) {
|
||||
thenExpression.replace(JavaPsiFacade.getElementFactory(project).createExpressionFromText(
|
||||
conditionalExpression.getCondition().getText() + "?" + thenExpression.getText() + ":" + elseExpression.getText(), thenExpression));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Push condition 'b' inside method call" "true"
|
||||
class Foo {
|
||||
void bar(boolean b){
|
||||
String s = foo(b ? "true" : "false");
|
||||
}
|
||||
String foo(String p) {return p;}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Push condition 'b' inside method call" "true"
|
||||
class Foo {
|
||||
void bar(boolean b){
|
||||
String s = foo(b ? "true" : "false", true).substring(0);
|
||||
}
|
||||
String foo(String p, boolean b) {return p;}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Push condition 'b' inside method call" "true"
|
||||
class Foo {
|
||||
void bar(boolean b){
|
||||
String s = foo("true", true).substring(b ? 1 : 2).substring(0);
|
||||
}
|
||||
String foo(String p, boolean b) {return p;}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Push condition 'b' inside method call" "true"
|
||||
class Foo {
|
||||
void bar(boolean b){
|
||||
String s = b <caret>? foo("true") : foo("false");
|
||||
}
|
||||
String foo(String p) {return p;}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
// "Push condition 'b' inside method call" "false"
|
||||
class Foo {
|
||||
void bar(boolean b){
|
||||
String s = b <caret>? foo("true") : foo(false);
|
||||
}
|
||||
String foo(String p) {return p;}
|
||||
String foo(boolean b) {return "false";}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Push condition 'b' inside method call" "true"
|
||||
class Foo {
|
||||
void bar(boolean b){
|
||||
String s = b <caret>? foo("true", true).substring(0) : foo("false", true).substring(0);
|
||||
}
|
||||
String foo(String p, boolean b) {return p;}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Push condition 'b' inside method call" "false"
|
||||
class Foo {
|
||||
void bar(boolean b){
|
||||
String s = b <caret>? foo("true", true).substring(0) : foo("false", true).substring(1);
|
||||
}
|
||||
String foo(String p, boolean b) {return p;}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Push condition 'b' inside method call" "true"
|
||||
class Foo {
|
||||
void bar(boolean b){
|
||||
String s = b <caret>? foo("true", true).substring(1).substring(0) : foo("true", true).substring(2).substring(0);
|
||||
}
|
||||
String foo(String p, boolean b) {return p;}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Push condition 'b' inside method call" "false"
|
||||
class Foo {
|
||||
void bar(boolean b){
|
||||
String s = b <caret>? foo("true", true) : foo("false", false);
|
||||
}
|
||||
String foo(String p, boolean b) {return p;}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.codeInsight.daemon.quickFix;
|
||||
|
||||
public class PushConditionInCallTest extends LightQuickFixParameterizedTestCase {
|
||||
public void test() throws Exception { doAllTests(); }
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/pushConditionInCall";
|
||||
}
|
||||
}
|
||||
@@ -117,12 +117,12 @@ public class ConditionalCanBePushedInsideExpressionInspection extends BaseInspec
|
||||
if (match.isExactMismatch() || match.isExactMatch()) {
|
||||
return;
|
||||
}
|
||||
registerError(expression, ignoreSingleArgument && isOnlyArgumentOfMethodCall(match.getLeftDiff())
|
||||
registerError(expression, ignoreSingleArgument && isOnlyArgumentOfMethodCall(match.getLeftDiff(), expression)
|
||||
? ProblemHighlightType.INFORMATION
|
||||
: ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
|
||||
}
|
||||
|
||||
private boolean isOnlyArgumentOfMethodCall(PsiElement element) {
|
||||
private boolean isOnlyArgumentOfMethodCall(PsiElement element, PsiConditionalExpression conditional) {
|
||||
if (element == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -135,7 +135,11 @@ public class ConditionalCanBePushedInsideExpressionInspection extends BaseInspec
|
||||
return false;
|
||||
}
|
||||
final PsiElement grandParent = expressionList.getParent();
|
||||
return grandParent instanceof PsiMethodCallExpression;
|
||||
if (!(grandParent instanceof PsiMethodCallExpression)) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement greatGrandParent = ParenthesesUtils.getParentSkipParentheses(grandParent);
|
||||
return greatGrandParent == conditional;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,13 +71,23 @@ public class EquivalenceChecker {
|
||||
return myExactlyMatches != null && !myExactlyMatches;
|
||||
}
|
||||
|
||||
Match setConcreteIfExactMismatch(PsiElement left, PsiElement right) {
|
||||
Match partialIfExactMismatch(PsiElement left, PsiElement right) {
|
||||
return this == EXACT_MISMATCH ? new Match(left, right) : this;
|
||||
}
|
||||
|
||||
static Match exact(boolean exactMatches) {
|
||||
return exactMatches ? EXACT_MATCH : EXACT_MISMATCH;
|
||||
}
|
||||
|
||||
Match combine(Match other) {
|
||||
if (other.isExactMismatch() || isExactMatch()) {
|
||||
return other;
|
||||
}
|
||||
if (isExactMismatch() || other.isExactMatch()) {
|
||||
return this;
|
||||
}
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean statementsAreEquivalent(@Nullable PsiStatement statement1, @Nullable PsiStatement statement2) {
|
||||
@@ -208,7 +218,7 @@ public class EquivalenceChecker {
|
||||
}
|
||||
final PsiExpression initializer1 = localVariable1.getInitializer();
|
||||
final PsiExpression initializer2 = localVariable2.getInitializer();
|
||||
return expressionsMatch(initializer1, initializer2).setConcreteIfExactMismatch(initializer1, initializer2);
|
||||
return expressionsMatch(initializer1, initializer2).partialIfExactMismatch(initializer1, initializer2);
|
||||
}
|
||||
|
||||
protected Match tryStatementsMatch(@NotNull PsiTryStatement statement1, @NotNull PsiTryStatement statement2) {
|
||||
@@ -333,7 +343,7 @@ public class EquivalenceChecker {
|
||||
}
|
||||
final PsiStatement body1 = statement1.getBody();
|
||||
final PsiStatement body2 = statement2.getBody();
|
||||
return statementsMatch(body1, body2).setConcreteIfExactMismatch(body1, body2);
|
||||
return statementsMatch(body1, body2).partialIfExactMismatch(body1, body2);
|
||||
}
|
||||
|
||||
protected Match forEachStatementsMatch(@NotNull PsiForeachStatement statement1, @NotNull PsiForeachStatement statement2) {
|
||||
@@ -357,7 +367,7 @@ public class EquivalenceChecker {
|
||||
}
|
||||
final PsiStatement body1 = statement1.getBody();
|
||||
final PsiStatement body2 = statement2.getBody();
|
||||
return statementsMatch(body1, body2).setConcreteIfExactMismatch(body1, body2);
|
||||
return statementsMatch(body1, body2).partialIfExactMismatch(body1, body2);
|
||||
}
|
||||
|
||||
protected Match switchStatementsMatch(@NotNull PsiSwitchStatement statement1, @NotNull PsiSwitchStatement statement2) {
|
||||
@@ -369,7 +379,7 @@ public class EquivalenceChecker {
|
||||
if (bodyEq != EXACT_MATCH) {
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
return expressionsMatch(switchExpression1, switchExpression2).setConcreteIfExactMismatch(switchExpression1, switchExpression2);
|
||||
return expressionsMatch(switchExpression1, switchExpression2).partialIfExactMismatch(switchExpression1, switchExpression2);
|
||||
}
|
||||
|
||||
protected Match doWhileStatementsMatch(@NotNull PsiDoWhileStatement statement1, @NotNull PsiDoWhileStatement statement2) {
|
||||
@@ -445,7 +455,7 @@ public class EquivalenceChecker {
|
||||
}
|
||||
final PsiExpression caseExpression1 = statement1.getCaseValue();
|
||||
final PsiExpression caseExpression2 = statement2.getCaseValue();
|
||||
return expressionsMatch(caseExpression1, caseExpression2).setConcreteIfExactMismatch(caseExpression1, caseExpression2);
|
||||
return expressionsMatch(caseExpression1, caseExpression2).partialIfExactMismatch(caseExpression1, caseExpression2);
|
||||
}
|
||||
|
||||
protected Match labeledStatementsMatch(@NotNull PsiLabeledStatement statement1, @NotNull PsiLabeledStatement statement2) {
|
||||
@@ -525,7 +535,7 @@ public class EquivalenceChecker {
|
||||
final PsiExpressionList expressionList2 =
|
||||
statement2.getExpressionList();
|
||||
final PsiExpression[] expressions2 = expressionList2.getExpressions();
|
||||
return expressionListsAreEquivalent(expressions1, expressions2);
|
||||
return expressionsAreEquivalent(expressions1, expressions2);
|
||||
}
|
||||
|
||||
public boolean expressionsAreEquivalent(@Nullable PsiExpression expression1, @Nullable PsiExpression expression2) {
|
||||
@@ -594,9 +604,57 @@ public class EquivalenceChecker {
|
||||
if (expression1 instanceof PsiInstanceOfExpression) {
|
||||
return instanceOfExpressionsMatch((PsiInstanceOfExpression)expression1, (PsiInstanceOfExpression)expression2);
|
||||
}
|
||||
if (expression1 instanceof PsiLambdaExpression) {
|
||||
return lambdaExpressionsMatch((PsiLambdaExpression)expression1, (PsiLambdaExpression)expression2);
|
||||
}
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
|
||||
protected Match lambdaExpressionsMatch(PsiLambdaExpression expression1, PsiLambdaExpression expression2) {
|
||||
final PsiParameterList parameterList1 = expression1.getParameterList();
|
||||
final PsiParameterList parameterList2 = expression2.getParameterList();
|
||||
final PsiParameter[] parameters1 = parameterList1.getParameters();
|
||||
final PsiParameter[] parameters2 = parameterList2.getParameters();
|
||||
if (parameters1.length != parameters2.length) {
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
for (int i = 0, length = parameters1.length; i < length; i++) {
|
||||
if (!parametersAreEquivalent(parameters1[i], parameters2[i]).isExactMatch()) {
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
}
|
||||
final PsiElement body1 = unwrapLambdaBody(expression1.getBody());
|
||||
final PsiElement body2 = unwrapLambdaBody(expression2.getBody());
|
||||
if (body1 instanceof PsiCodeBlock && body2 instanceof PsiCodeBlock) {
|
||||
return codeBlocksMatch((PsiCodeBlock)body1, (PsiCodeBlock)body2);
|
||||
}
|
||||
else if (body1 instanceof PsiExpression && body2 instanceof PsiExpression) {
|
||||
return expressionsMatch((PsiExpression)body1, (PsiExpression)body2);
|
||||
}
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
|
||||
private static PsiElement unwrapLambdaBody(PsiElement element) {
|
||||
while (element instanceof PsiCodeBlock) {
|
||||
final PsiCodeBlock codeBlock = (PsiCodeBlock)element;
|
||||
final PsiStatement[] statements = codeBlock.getStatements();
|
||||
if (statements.length != 1) {
|
||||
break;
|
||||
}
|
||||
final PsiStatement statement = statements[0];
|
||||
if (statement instanceof PsiReturnStatement) {
|
||||
return ((PsiReturnStatement)statement).getReturnValue();
|
||||
}
|
||||
else if (statement instanceof PsiExpressionStatement) {
|
||||
return ((PsiExpressionStatement)statement).getExpression();
|
||||
}
|
||||
else if (statement instanceof PsiBlockStatement) {
|
||||
element = ((PsiBlockStatement)statement).getCodeBlock();
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
protected Match literalExpressionsMatch(PsiLiteralExpression expression1, PsiLiteralExpression expression2) {
|
||||
final Object value1 = expression1.getValue();
|
||||
final Object value2 = expression2.getValue();
|
||||
@@ -679,20 +737,17 @@ public class EquivalenceChecker {
|
||||
}
|
||||
|
||||
protected Match methodCallExpressionsMatch(@NotNull PsiMethodCallExpression methodCallExpression1, @NotNull PsiMethodCallExpression methodCallExpression2) {
|
||||
final PsiReferenceExpression methodExpression1 =
|
||||
methodCallExpression1.getMethodExpression();
|
||||
final PsiReferenceExpression methodExpression2 =
|
||||
methodCallExpression2.getMethodExpression();
|
||||
if (!expressionsMatch(methodExpression1, methodExpression2).isExactMatch()) {
|
||||
final PsiReferenceExpression methodExpression1 = methodCallExpression1.getMethodExpression();
|
||||
final PsiReferenceExpression methodExpression2 = methodCallExpression2.getMethodExpression();
|
||||
Match match = expressionsMatch(methodExpression1, methodExpression2);
|
||||
if (match.isExactMismatch()) {
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
final PsiExpressionList argumentList1 =
|
||||
methodCallExpression1.getArgumentList();
|
||||
final PsiExpressionList argumentList1 = methodCallExpression1.getArgumentList();
|
||||
final PsiExpression[] args1 = argumentList1.getExpressions();
|
||||
final PsiExpressionList argumentList2 =
|
||||
methodCallExpression2.getArgumentList();
|
||||
final PsiExpressionList argumentList2 = methodCallExpression2.getArgumentList();
|
||||
final PsiExpression[] args2 = argumentList2.getExpressions();
|
||||
final Match match = expressionListsAreEquivalent(args1, args2);
|
||||
match = match.combine(expressionsAreEquivalent(args1, args2));
|
||||
|
||||
if (match.isPartialMatch()) {
|
||||
final PsiElement leftDiff = match.getLeftDiff();
|
||||
@@ -732,7 +787,7 @@ public class EquivalenceChecker {
|
||||
newExpression1.getArrayDimensions();
|
||||
final PsiExpression[] arrayDimensions2 =
|
||||
newExpression2.getArrayDimensions();
|
||||
if (!expressionListsAreEquivalent(arrayDimensions1, arrayDimensions2).isExactMatch()) {
|
||||
if (!expressionsAreEquivalent(arrayDimensions1, arrayDimensions2).isExactMatch()) {
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
final PsiArrayInitializerExpression arrayInitializer1 =
|
||||
@@ -756,7 +811,7 @@ public class EquivalenceChecker {
|
||||
final PsiExpression[] args1 = argumentList1 == null ? null : argumentList1.getExpressions();
|
||||
final PsiExpressionList argumentList2 = newExpression2.getArgumentList();
|
||||
final PsiExpression[] args2 = argumentList2 == null ? null : argumentList2.getExpressions();
|
||||
return expressionListsAreEquivalent(args1, args2);
|
||||
return expressionsAreEquivalent(args1, args2);
|
||||
}
|
||||
|
||||
protected Match arrayInitializerExpressionsMatch(@NotNull PsiArrayInitializerExpression arrayInitializerExpression1, @NotNull PsiArrayInitializerExpression arrayInitializerExpression2) {
|
||||
@@ -764,7 +819,7 @@ public class EquivalenceChecker {
|
||||
arrayInitializerExpression1.getInitializers();
|
||||
final PsiExpression[] initializers2 =
|
||||
arrayInitializerExpression2.getInitializers();
|
||||
return expressionListsAreEquivalent(initializers1, initializers2);
|
||||
return expressionsAreEquivalent(initializers1, initializers2);
|
||||
}
|
||||
|
||||
protected Match typeCastExpressionsMatch(@NotNull PsiTypeCastExpression typeCastExpression1, @NotNull PsiTypeCastExpression typeCastExpression2) {
|
||||
@@ -778,7 +833,7 @@ public class EquivalenceChecker {
|
||||
if (operand1 instanceof PsiFunctionalExpression || operand2 instanceof PsiFunctionalExpression) {
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
return expressionsMatch(operand1, operand2).setConcreteIfExactMismatch(operand1, operand2);
|
||||
return expressionsMatch(operand1, operand2).partialIfExactMismatch(operand1, operand2);
|
||||
}
|
||||
|
||||
protected Match arrayAccessExpressionsMatch(@NotNull PsiArrayAccessExpression arrayAccessExpression1, @NotNull PsiArrayAccessExpression arrayAccessExpression2) {
|
||||
@@ -794,7 +849,7 @@ public class EquivalenceChecker {
|
||||
if (arrayExpressionEq != EXACT_MATCH) {
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
return expressionsMatch(indexExpression1, indexExpression2).setConcreteIfExactMismatch(indexExpression1, indexExpression2);
|
||||
return expressionsMatch(indexExpression1, indexExpression2).partialIfExactMismatch(indexExpression1, indexExpression2);
|
||||
}
|
||||
|
||||
protected Match prefixExpressionsMatch(@NotNull PsiPrefixExpression prefixExpression1, @NotNull PsiPrefixExpression prefixExpression2) {
|
||||
@@ -825,24 +880,7 @@ public class EquivalenceChecker {
|
||||
}
|
||||
final PsiExpression[] operands1 = polyadicExpression1.getOperands();
|
||||
final PsiExpression[] operands2 = polyadicExpression2.getOperands();
|
||||
if (operands1.length != operands2.length) {
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
|
||||
Match incompleteMatch = null;
|
||||
for (int i = 0; i < operands1.length; i++) {
|
||||
final Match match = expressionsMatch(operands1[i], operands2[i]);
|
||||
if (!match.isExactMatch()) {
|
||||
if (incompleteMatch == null) {
|
||||
incompleteMatch =
|
||||
match.isExactMismatch() ? new Match(operands1[i], operands2[i]) : match;
|
||||
}
|
||||
else {
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
return incompleteMatch != null ? incompleteMatch : EXACT_MATCH;
|
||||
return expressionsAreEquivalent(operands1, operands2);
|
||||
}
|
||||
|
||||
protected Match assignmentExpressionsMatch(@NotNull PsiAssignmentExpression assignmentExpression1, @NotNull PsiAssignmentExpression assignmentExpression2) {
|
||||
@@ -878,7 +916,7 @@ public class EquivalenceChecker {
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
|
||||
protected Match expressionListsAreEquivalent(@Nullable PsiExpression[] expressions1, @Nullable PsiExpression[] expressions2) {
|
||||
protected Match expressionsAreEquivalent(@Nullable PsiExpression[] expressions1, @Nullable PsiExpression[] expressions2) {
|
||||
if (expressions1 == null && expressions2 == null) {
|
||||
return EXACT_MATCH;
|
||||
}
|
||||
@@ -892,13 +930,14 @@ public class EquivalenceChecker {
|
||||
Match incompleteMatch = null;
|
||||
for (int i = 0; i < expressions1.length; i++) {
|
||||
final Match match = expressionsMatch(expressions1[i], expressions2[i]);
|
||||
if (!match.isExactMatch()) {
|
||||
if (incompleteMatch == null) {
|
||||
incompleteMatch = match.isExactMismatch() ? new Match(expressions1[i], expressions2[i]) : match;
|
||||
}
|
||||
else {
|
||||
if (incompleteMatch == null && match.isPartialMatch()) {
|
||||
incompleteMatch = match;
|
||||
}
|
||||
else if (!match.isExactMatch()) {
|
||||
if (incompleteMatch != null) {
|
||||
return EXACT_MISMATCH;
|
||||
}
|
||||
incompleteMatch = match.partialIfExactMismatch(expressions1[i], expressions2[i]);
|
||||
}
|
||||
}
|
||||
return incompleteMatch == null ? EXACT_MATCH : incompleteMatch;
|
||||
|
||||
@@ -53,4 +53,16 @@ class ConditionalCanBePushedInsideExpression {
|
||||
}
|
||||
}
|
||||
|
||||
void bar(boolean b){
|
||||
String s = <warning descr="Conditional expression can be pushed inside branch">b ? foo(bar("true"), true).substring(1) : foo(bar("false"), true).substring(1)</warning>;
|
||||
String t = <warning descr="Conditional expression can be pushed inside branch">b ? foo("true", true).substring(1).substring(0) : foo("true", true).substring(2).substring(0)</warning>;
|
||||
String u = <warning descr="Conditional expression can be pushed inside branch">b ? foo("true", true).substring(0) : foo("false", true).substring(0)</warning>;
|
||||
String v = <warning descr="Conditional expression can be pushed inside branch">b ? bar(bar("one")) : bar(bar("two"))</warning>;
|
||||
}
|
||||
|
||||
String foo(String p, boolean b) {return p;}
|
||||
String bar(String s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,6 +35,11 @@ class ConditionalExpressionWithIdenticalBranches {
|
||||
static class WithFunctionalExpression {
|
||||
private void foo(boolean b) {
|
||||
Runnable r = b ? (Runnable) () -> {} : (Runnable) () -> {};
|
||||
IntSupplier s = <warning descr="Conditional expression 'b ? () -> 1 : () -> { return 1; }' with identical branches">b ? () -> 1 : () -> { return 1; }</warning>;
|
||||
}
|
||||
}
|
||||
|
||||
interface IntSupplier {
|
||||
int getAsInt();
|
||||
}
|
||||
}
|
||||
@@ -1064,10 +1064,6 @@
|
||||
<className>com.intellij.codeInsight.intention.impl.JoinDeclarationAndAssignmentAction</className>
|
||||
<category>Java/Declaration</category>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.intention.impl.PushConditionInCallAction</className>
|
||||
<category>Java/Declaration</category>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.intention.impl.MoveInitializerToConstructorAction</className>
|
||||
<category>Java/Declaration</category>
|
||||
|
||||
Reference in New Issue
Block a user