mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-05 01:50:56 +07:00
IDEA-85758 intention to replace casted var with a var of the right type and having the same value implemented
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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.CodeInsightBundle;
|
||||
import com.intellij.codeInsight.CodeInsightUtil;
|
||||
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Danila Ponomarenko
|
||||
*/
|
||||
public class ReplaceCastWithVariableAction extends PsiElementBaseIntentionAction {
|
||||
private String myReplaceVariableName = "";
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
|
||||
final PsiTypeCastExpression typeCastExpression = PsiTreeUtil.getParentOfType(element, PsiTypeCastExpression.class);
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class);
|
||||
|
||||
if (typeCastExpression == null || method == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiExpression operand = typeCastExpression.getOperand();
|
||||
if (!(operand instanceof PsiReferenceExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiReferenceExpression operandReference = (PsiReferenceExpression)operand;
|
||||
final PsiElement resolved = operandReference.resolve();
|
||||
if (resolved == null || (!(resolved instanceof PsiParameter) && !(resolved instanceof PsiLocalVariable))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiLocalVariable replacement = findReplacement(method, (PsiVariable)resolved, typeCastExpression);
|
||||
if (replacement == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
myReplaceVariableName = replacement.getName();
|
||||
setText(CodeInsightBundle.message("intention.replace.cast.with.var.text", typeCastExpression.getText(), myReplaceVariableName));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
|
||||
final PsiTypeCastExpression typeCastExpression = PsiTreeUtil.getParentOfType(element, PsiTypeCastExpression.class);
|
||||
|
||||
if (typeCastExpression == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiElement toReplace = typeCastExpression.getParent() instanceof PsiParenthesizedExpression ? typeCastExpression.getParent() : typeCastExpression;
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
toReplace.replace(factory.createExpressionFromText(myReplaceVariableName, toReplace));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiLocalVariable findReplacement(@NotNull PsiMethod method,
|
||||
@NotNull PsiVariable castedVar,
|
||||
@NotNull PsiTypeCastExpression expression) {
|
||||
final TextRange expressionTextRange = expression.getTextRange();
|
||||
for (PsiExpression occurrence : CodeInsightUtil.findExpressionOccurrences(method,expression)){
|
||||
ProgressIndicatorProvider.checkCanceled();
|
||||
final TextRange occurrenceTextRange = occurrence.getTextRange();
|
||||
if (occurrence == expression || occurrenceTextRange.getEndOffset() >= expressionTextRange.getStartOffset()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final PsiLocalVariable variable = getVariable(occurrence);
|
||||
|
||||
final PsiCodeBlock methodBody = method.getBody();
|
||||
if (variable != null && methodBody != null &&
|
||||
!isChangedBetween(castedVar, methodBody, occurrence, expression) && !isChangedBetween(variable, methodBody, occurrence, expression)) {
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isChangedBetween(@NotNull final PsiVariable variable,
|
||||
@NotNull final PsiElement scope,
|
||||
@NotNull final PsiElement start,
|
||||
@NotNull final PsiElement end) {
|
||||
if (variable.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Ref<Boolean> result = new Ref<Boolean>();
|
||||
|
||||
scope.accept(
|
||||
new JavaRecursiveElementWalkingVisitor() {
|
||||
private boolean inScope = false;
|
||||
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (element == start) {
|
||||
inScope = true;
|
||||
}
|
||||
if (element == end) {
|
||||
inScope = false;
|
||||
stopWalking();
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAssignmentExpression(PsiAssignmentExpression expression) {
|
||||
if (inScope && expression.getLExpression() instanceof PsiReferenceExpression) {
|
||||
final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)expression.getLExpression();
|
||||
|
||||
if (variable.equals(referenceExpression.resolve())) {
|
||||
result.set(true);
|
||||
stopWalking();
|
||||
}
|
||||
}
|
||||
super.visitAssignmentExpression(expression);
|
||||
}
|
||||
}
|
||||
);
|
||||
return result.get() == Boolean.TRUE;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiLocalVariable getVariable(@NotNull PsiExpression occurrence) {
|
||||
final PsiElement parent = occurrence.getParent();
|
||||
|
||||
if (parent instanceof PsiLocalVariable) {
|
||||
return (PsiLocalVariable)parent;
|
||||
}
|
||||
|
||||
if (parent instanceof PsiAssignmentExpression) {
|
||||
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent;
|
||||
if (assignmentExpression.getLExpression() instanceof PsiReferenceExpression) {
|
||||
final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)assignmentExpression.getLExpression();
|
||||
final PsiElement resolved = referenceExpression.resolve();
|
||||
if (resolved instanceof PsiLocalVariable) {
|
||||
return (PsiLocalVariable)resolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return CodeInsightBundle.message("intention.replace.cast.with.var.family");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "true"
|
||||
|
||||
import java.lang.Object;
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
FooBar foobar = (FooBar)foo;
|
||||
Object o = foobar.baz;
|
||||
foo = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "true"
|
||||
|
||||
import java.lang.Object;
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
FooBar foobar = (FooBar)foo;
|
||||
Object o = foobar.baz;
|
||||
foobar = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "true"
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
foo = null;
|
||||
FooBar foobar = (FooBar)foo;
|
||||
return foobar.baz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "true"
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
foobar = null;
|
||||
FooBar foobar = (FooBar)foo;
|
||||
return foobar.baz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "true"
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
FooBar foobar = (FooBar)foo;
|
||||
foobar = null;
|
||||
foo = null;
|
||||
foobar = (FooBar)foo;
|
||||
return foobar.baz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "true"
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
FooBar foobar = (FooBar)foo;
|
||||
return foobar.baz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar2'" "true"
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
FooBar foobar = (FooBar)foo;
|
||||
foobar = null;
|
||||
FooBar foobar2 = (FooBar)foo;
|
||||
return foobar2.baz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "true"
|
||||
|
||||
import java.lang.Object;
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
FooBar foobar = (FooBar)foo;
|
||||
Object o = ((FooBar<caret>)foo).baz;
|
||||
foo = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "true"
|
||||
|
||||
import java.lang.Object;
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
FooBar foobar = (FooBar)foo;
|
||||
Object o = ((FooBar<caret>)foo).baz;
|
||||
foobar = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "true"
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
foo = null;
|
||||
FooBar foobar = (FooBar)foo;
|
||||
return ((FooBar<caret>)foo).baz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "true"
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
foobar = null;
|
||||
FooBar foobar = (FooBar)foo;
|
||||
return ((FooBar<caret>)foo).baz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "false"
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
FooBar foobar = (FooBar)foo;
|
||||
foo = null;
|
||||
return ((FooBar<caret>)foo).baz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "true"
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
FooBar foobar = (FooBar)foo;
|
||||
foobar = null;
|
||||
foo = null;
|
||||
foobar = (FooBar)foo;
|
||||
return ((FooBar<caret>)foo).baz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "false"
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
FooBar foobar = (FooBar)foo;
|
||||
foobar = null;
|
||||
return ((FooBar<caret>)foo).baz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar'" "true"
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
FooBar foobar = (FooBar)foo;
|
||||
return ((FooBar<caret>)foo).baz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace '(FooBar)foo' with 'foobar2'" "true"
|
||||
|
||||
class FooBar {
|
||||
public int baz;
|
||||
|
||||
int method(Object foo) {
|
||||
FooBar foobar = (FooBar)foo;
|
||||
foobar = null;
|
||||
FooBar foobar2 = (FooBar)foo;
|
||||
return ((FooBar<caret>)foo).baz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.intellij.codeInsight.daemon.LightIntentionActionTestCase;
|
||||
|
||||
/**
|
||||
* @author Danila Ponomarenko
|
||||
*/
|
||||
public class ReplaceCastWithVariableTest extends LightIntentionActionTestCase {
|
||||
|
||||
public void test() throws Exception { doAllTests(); }
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/replaceCastWithVariable";
|
||||
}
|
||||
}
|
||||
@@ -205,7 +205,7 @@ intention.extract.if.condition.family=Extract If Condition
|
||||
intention.underscores.in.literals.family=Underscores in numeric literals
|
||||
intention.remove.literal.underscores=Remove underscores from literal
|
||||
intention.insert.literal.underscores=Insert underscores into literal
|
||||
intention.replace.cast.with.var.text=Replace '{0}' with '{1}'
|
||||
intention.replace.cast.with.var.text=Replace ''{0}'' with ''{1}''
|
||||
intention.replace.cast.with.var.family=Replace cast with variable
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
FooBar foobar = (FooBar) foo;
|
||||
return foobar.baz;
|
||||
@@ -0,0 +1,2 @@
|
||||
FooBar foobar = (FooBar) foo;
|
||||
return <spot>((FooBar) foo)</spot>.baz;
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention replaces type cast expression with existing local variable having the same value.
|
||||
</body>
|
||||
</html>
|
||||
@@ -710,10 +710,10 @@
|
||||
<category>Other</category>
|
||||
</intentionAction>
|
||||
|
||||
<!--<intentionAction>-->
|
||||
<!--<className>com.intellij.codeInsight.intention.impl.ReplaceCastAction</className>-->
|
||||
<!--<category>Other</category>-->
|
||||
<!--</intentionAction>-->
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.intention.impl.ReplaceCastWithVariableAction</className>
|
||||
<category>Other</category>
|
||||
</intentionAction>
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user