Inline Variable: Var support

#KT-5169 Fixed
This commit is contained in:
Alexey Sedunov
2015-09-28 19:28:12 +03:00
parent 007c7c17f0
commit e3d8d819da
9 changed files with 70 additions and 18 deletions
@@ -54,18 +54,20 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory; import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.idea.JetLanguage; import org.jetbrains.kotlin.idea.JetLanguage;
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade;
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils; import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade;
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers; import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
import org.jetbrains.kotlin.idea.util.ShortenReferences; import org.jetbrains.kotlin.idea.util.ShortenReferences;
import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.JetPsiUtilKt;
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode; import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode;
import org.jetbrains.kotlin.types.ErrorUtils; import org.jetbrains.kotlin.types.ErrorUtils;
import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.expressions.OperatorConventions;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -85,7 +87,7 @@ public class KotlinInlineValHandler extends InlineActionHandler {
return false; return false;
} }
JetProperty property = (JetProperty) element; JetProperty property = (JetProperty) element;
return !property.isVar() && property.getGetter() == null && property.getReceiverTypeReference() == null; return property.getGetter() == null && property.getReceiverTypeReference() == null;
} }
@Override @Override
@@ -101,9 +103,15 @@ public class KotlinInlineValHandler extends InlineActionHandler {
final Set<PsiElement> assignments = Sets.newHashSet(); final Set<PsiElement> assignments = Sets.newHashSet();
for (JetExpression expression : referenceExpressions) { for (JetExpression expression : referenceExpressions) {
PsiElement parent = expression.getParent(); PsiElement parent = expression.getParent();
if (parent instanceof JetBinaryExpression &&
((JetBinaryExpression) parent).getOperationToken() == JetTokens.EQ && JetBinaryExpression assignment = JetPsiUtilKt.getAssignmentByLHS(expression);
((JetBinaryExpression) parent).getLeft() == expression) { if (assignment != null) {
assignments.add(parent);
}
//noinspection SuspiciousMethodCalls
if (parent instanceof JetUnaryExpression &&
OperatorConventions.INCREMENT_OPERATIONS.contains(((JetUnaryExpression) parent).getOperationToken())) {
assignments.add(parent); assignments.add(parent);
} }
} }
@@ -111,6 +119,10 @@ public class KotlinInlineValHandler extends InlineActionHandler {
final JetExpression initializer; final JetExpression initializer;
if (initializerInDeclaration != null) { if (initializerInDeclaration != null) {
initializer = initializerInDeclaration; initializer = initializerInDeclaration;
if (!assignments.isEmpty()) {
reportAmbiguousAssignment(project, editor, name, assignments);
return;
}
} }
else { else {
if (assignments.size() == 1) { if (assignments.size() == 1) {
@@ -120,9 +132,7 @@ public class KotlinInlineValHandler extends InlineActionHandler {
initializer = null; initializer = null;
} }
if (initializer == null) { if (initializer == null) {
String key = assignments.isEmpty() ? "variable.has.no.initializer" : "variable.has.no.dominating.definition"; reportAmbiguousAssignment(project, editor, name, assignments);
String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message(key, name));
CommonRefactoringUtil.showErrorHint(project, editor, message, RefactoringBundle.message("inline.variable.title"), HelpID.INLINE_VARIABLE);
return; return;
} }
} }
@@ -196,6 +206,23 @@ public class KotlinInlineValHandler extends InlineActionHandler {
null); null);
} }
private static void reportAmbiguousAssignment(Project project, Editor editor, String name, Set<PsiElement> assignments) {
String key = assignments.isEmpty() ? "variable.has.no.initializer" : "variable.has.no.dominating.definition";
String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message(key, name));
showErrorHint(project, editor, message);
}
private static void reportWriteAccess(Project project, Editor editor, String name) {
String message = RefactoringBundle.getCannotRefactorMessage(
RefactoringBundle.message("variable.is.accessed.for.writing", name)
);
showErrorHint(project, editor, message);
}
private static void showErrorHint(Project project, Editor editor, String message) {
CommonRefactoringUtil.showErrorHint(project, editor, message, RefactoringBundle.message("inline.variable.title"), HelpID.INLINE_VARIABLE);
}
private static void highlightExpressions(Project project, Editor editor, List<? extends PsiElement> elements) { private static void highlightExpressions(Project project, Editor editor, List<? extends PsiElement> elements) {
if (editor == null || ApplicationManager.getApplication().isUnitTestMode()) { if (editor == null || ApplicationManager.getApplication().isUnitTestMode()) {
return; return;
-4
View File
@@ -1,4 +0,0 @@
fun f() {
var v = 239
println(<caret>v)
}
@@ -1,3 +1,4 @@
// ERROR: Cannot perform refactoring.\nCannot find a single definition to inline
fun f() { fun f() {
val v = if (true) a else b val v = if (true) a else b
println(<caret>v++) println(<caret>v++)
@@ -1,3 +0,0 @@
fun f() {
println((if (true) a else b)++)
}
+4
View File
@@ -0,0 +1,4 @@
fun foo() {
var x = 1
val t = <caret>x + 1
}
+3
View File
@@ -0,0 +1,3 @@
fun foo() {
val t = 1 + 1
}
+6
View File
@@ -0,0 +1,6 @@
// ERROR: Cannot perform refactoring.\nCannot find a single definition to inline
fun foo() {
var x = 1
val t = <caret>x + 1
x = 2
}
+6
View File
@@ -0,0 +1,6 @@
// ERROR: Cannot perform refactoring.\nCannot find a single definition to inline
fun foo() {
var x = 1
val t = <caret>x + 1
x++
}
@@ -101,9 +101,21 @@ public class InlineTestGenerated extends AbstractInlineTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("Var.kt") @TestMetadata("varNoWrite.kt")
public void testVar() throws Exception { public void testVarNoWrite() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/inline/Var.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/inline/varNoWrite.kt");
doTest(fileName);
}
@TestMetadata("varWithAssignment.kt")
public void testVarWithAssignment() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/inline/varWithAssignment.kt");
doTest(fileName);
}
@TestMetadata("varWithInc.kt")
public void testVarWithInc() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/inline/varWithInc.kt");
doTest(fileName); doTest(fileName);
} }