Fixed KT-2072: do not suggest to use type inference in Introduce Variable in case if expression type depends on expected type.
This commit is contained in:
@@ -21,10 +21,10 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.ui.popup.JBPopupAdapter;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -85,7 +85,8 @@ public class JetRefactoringUtil {
|
||||
return;
|
||||
}
|
||||
ArrayList<JetExpression> expressions = new ArrayList<JetExpression>();
|
||||
while (element != null && !(element instanceof JetBlockExpression) && !(element instanceof JetNamedFunction)
|
||||
while (element != null && !(element instanceof JetBlockExpression && !(element.getParent() instanceof JetFunctionLiteral)) &&
|
||||
!(element instanceof JetNamedFunction)
|
||||
&& !(element instanceof JetClassBody) && !(element instanceof JetSecondaryConstructor)) {
|
||||
if (element instanceof JetExpression && !(element instanceof JetStatementExpression)) {
|
||||
boolean addExpression = true;
|
||||
@@ -132,7 +133,6 @@ public class JetRefactoringUtil {
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
Component rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
JetExpression element = (JetExpression) value;
|
||||
if (element.isValid()) {
|
||||
setText(getExpressionShortText(element));
|
||||
@@ -179,7 +179,7 @@ public class JetRefactoringUtil {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JetExpression findExpression(@NotNull Editor editor, @NotNull PsiFile file,
|
||||
public static JetExpression findExpression(@NotNull Editor editor, @NotNull PsiFile file,
|
||||
int startOffset, int endOffset) throws IntroduceRefactoringException{
|
||||
PsiElement element = PsiTreeUtil.findElementOfClassAtRange(file, startOffset, endOffset, JetExpression.class);
|
||||
if (element == null || element.getTextRange().getStartOffset() != startOffset ||
|
||||
@@ -202,6 +202,66 @@ public class JetRefactoringUtil {
|
||||
return (JetExpression) element;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PsiElement[] findStatements(@NotNull PsiFile file, int startOffset, int endOffset) {
|
||||
PsiElement element1 = file.findElementAt(startOffset);
|
||||
PsiElement element2 = file.findElementAt(endOffset - 1);
|
||||
if (element1 instanceof PsiWhiteSpace) {
|
||||
startOffset = element1.getTextRange().getEndOffset();
|
||||
element1 = file.findElementAt(startOffset);
|
||||
}
|
||||
if (element2 instanceof PsiWhiteSpace) {
|
||||
endOffset = element2.getTextRange().getStartOffset();
|
||||
element2 = file.findElementAt(endOffset - 1);
|
||||
}
|
||||
if (element1 == null || element2 == null) return PsiElement.EMPTY_ARRAY;
|
||||
|
||||
PsiElement parent = PsiTreeUtil.findCommonParent(element1, element2);
|
||||
if (parent == null) return PsiElement.EMPTY_ARRAY;
|
||||
while (true) {
|
||||
if (parent instanceof JetBlockExpression) break;
|
||||
if (parent == null || parent instanceof JetFile) return PsiElement.EMPTY_ARRAY;
|
||||
parent = parent.getParent();
|
||||
}
|
||||
|
||||
if (!parent.equals(element1)) {
|
||||
while (!parent.equals(element1.getParent())) {
|
||||
element1 = element1.getParent();
|
||||
}
|
||||
}
|
||||
if (startOffset != element1.getTextRange().getStartOffset()) return PsiElement.EMPTY_ARRAY;
|
||||
|
||||
if (!parent.equals(element2)) {
|
||||
while (!parent.equals(element2.getParent())) {
|
||||
element2 = element2.getParent();
|
||||
}
|
||||
}
|
||||
if (endOffset != element2.getTextRange().getEndOffset()) return PsiElement.EMPTY_ARRAY;
|
||||
|
||||
PsiElement[] children = parent.getChildren();
|
||||
ArrayList<PsiElement> array = new ArrayList<PsiElement>();
|
||||
boolean flag = false;
|
||||
for (PsiElement child : children) {
|
||||
if (child.equals(element1)) {
|
||||
flag = true;
|
||||
}
|
||||
if (flag && !(child instanceof PsiWhiteSpace)) {
|
||||
array.add(child);
|
||||
}
|
||||
if (child.equals(element2)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (PsiElement element : array) {
|
||||
if (!(element instanceof JetExpression || element instanceof PsiWhiteSpace || element instanceof PsiComment)) {
|
||||
return PsiElement.EMPTY_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
return PsiUtilCore.toPsiElementArray(array);
|
||||
}
|
||||
|
||||
public static class IntroduceRefactoringException extends Exception {
|
||||
private String myMessage;
|
||||
|
||||
|
||||
+31
-2
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.jet.plugin.refactoring.introduceVariable;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
@@ -34,13 +35,24 @@ import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.di.InjectorForMacros;
|
||||
import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJvm;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
|
||||
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
|
||||
import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.NamespaceType;
|
||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.jet.plugin.codeInsight.ReferenceToClassesShortening;
|
||||
@@ -48,6 +60,7 @@ import org.jetbrains.jet.plugin.project.AnalyzeSingleFileUtil;
|
||||
import org.jetbrains.jet.plugin.refactoring.*;
|
||||
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@@ -97,7 +110,6 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
|
||||
return;
|
||||
} else if (expression.getParent() instanceof JetCallElement) {
|
||||
if (expression instanceof JetFunctionLiteralExpression) {
|
||||
noTypeInference = true;
|
||||
needParentheses = true;
|
||||
} else {
|
||||
showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.no.expression"));
|
||||
@@ -113,6 +125,23 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
|
||||
}
|
||||
BindingContext bindingContext = AnalyzeSingleFileUtil.getContextForSingleFile((JetFile)expression.getContainingFile());
|
||||
final JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); //can be null or error type
|
||||
JetScope scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expression);
|
||||
if (scope != null) {
|
||||
DataFlowInfo dataFlowInfo = bindingContext.get(BindingContext.NON_DEFAULT_EXPRESSION_DATA_FLOW, expression);
|
||||
if (dataFlowInfo == null) {
|
||||
dataFlowInfo = DataFlowInfo.EMPTY;
|
||||
}
|
||||
|
||||
ObservableBindingTrace bindingTrace = new ObservableBindingTrace(new BindingTraceContext());
|
||||
InjectorForMacros injector = new InjectorForMacros(project);
|
||||
JetType typeNoExpectedType = injector.getExpressionTypingServices().getType(scope, expression,
|
||||
TypeUtils.NO_EXPECTED_TYPE, dataFlowInfo,
|
||||
bindingTrace);
|
||||
if (expressionType != null && typeNoExpectedType != null && !JetTypeChecker.INSTANCE.equalTypes(expressionType,
|
||||
typeNoExpectedType)) {
|
||||
noTypeInference = true;
|
||||
}
|
||||
}
|
||||
if (expressionType instanceof NamespaceType) {
|
||||
showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.namespace.expression"));
|
||||
return;
|
||||
|
||||
@@ -3,7 +3,7 @@ fun foo(c : Collection<String>){
|
||||
}
|
||||
/*
|
||||
fun foo(c : Collection<String>){
|
||||
val function: () -> Boolean = {it; false}
|
||||
val function = {it; false}
|
||||
c.filter(function)
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,17 @@
|
||||
class A {
|
||||
fun foo() = 1
|
||||
}
|
||||
fun apply(x: (A) -> Int) = 2
|
||||
fun test() {
|
||||
apply<selection>{it.foo()}</selection>
|
||||
}
|
||||
/*
|
||||
class A {
|
||||
fun foo() = 1
|
||||
}
|
||||
fun apply(x: (A) -> Int) = 2
|
||||
fun test() {
|
||||
val function: (A) -> Int = {it.foo()}
|
||||
apply(function)
|
||||
}
|
||||
*/
|
||||
+4
@@ -57,6 +57,10 @@ public class JetIntroduceVariableTest extends LightCodeInsightFixtureTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testFunctionLiteralFromExpected() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIfCondition() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user