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.JBPopupAdapter;
|
||||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||||
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
|
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.*;
|
||||||
import com.intellij.psi.PsiFile;
|
|
||||||
import com.intellij.psi.PsiWhiteSpace;
|
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
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 com.intellij.ui.components.JBList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -85,7 +85,8 @@ public class JetRefactoringUtil {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ArrayList<JetExpression> expressions = new ArrayList<JetExpression>();
|
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)) {
|
&& !(element instanceof JetClassBody) && !(element instanceof JetSecondaryConstructor)) {
|
||||||
if (element instanceof JetExpression && !(element instanceof JetStatementExpression)) {
|
if (element instanceof JetExpression && !(element instanceof JetStatementExpression)) {
|
||||||
boolean addExpression = true;
|
boolean addExpression = true;
|
||||||
@@ -132,7 +133,6 @@ public class JetRefactoringUtil {
|
|||||||
@Override
|
@Override
|
||||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||||
Component rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
Component rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||||
StringBuilder buffer = new StringBuilder();
|
|
||||||
JetExpression element = (JetExpression) value;
|
JetExpression element = (JetExpression) value;
|
||||||
if (element.isValid()) {
|
if (element.isValid()) {
|
||||||
setText(getExpressionShortText(element));
|
setText(getExpressionShortText(element));
|
||||||
@@ -179,7 +179,7 @@ public class JetRefactoringUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@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{
|
int startOffset, int endOffset) throws IntroduceRefactoringException{
|
||||||
PsiElement element = PsiTreeUtil.findElementOfClassAtRange(file, startOffset, endOffset, JetExpression.class);
|
PsiElement element = PsiTreeUtil.findElementOfClassAtRange(file, startOffset, endOffset, JetExpression.class);
|
||||||
if (element == null || element.getTextRange().getStartOffset() != startOffset ||
|
if (element == null || element.getTextRange().getStartOffset() != startOffset ||
|
||||||
@@ -202,6 +202,66 @@ public class JetRefactoringUtil {
|
|||||||
return (JetExpression) element;
|
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 {
|
public static class IntroduceRefactoringException extends Exception {
|
||||||
private String myMessage;
|
private String myMessage;
|
||||||
|
|
||||||
|
|||||||
+31
-2
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.plugin.refactoring.introduceVariable;
|
package org.jetbrains.jet.plugin.refactoring.introduceVariable;
|
||||||
|
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
||||||
import com.intellij.openapi.actionSystem.DataContext;
|
import com.intellij.openapi.actionSystem.DataContext;
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
@@ -34,13 +35,24 @@ import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
|
|||||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
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.DeclarationDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
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.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.JetType;
|
||||||
import org.jetbrains.jet.lang.types.NamespaceType;
|
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.checker.JetTypeChecker;
|
||||||
|
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||||
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
|
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
import org.jetbrains.jet.plugin.codeInsight.ReferenceToClassesShortening;
|
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.plugin.refactoring.*;
|
||||||
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,7 +110,6 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
|
|||||||
return;
|
return;
|
||||||
} else if (expression.getParent() instanceof JetCallElement) {
|
} else if (expression.getParent() instanceof JetCallElement) {
|
||||||
if (expression instanceof JetFunctionLiteralExpression) {
|
if (expression instanceof JetFunctionLiteralExpression) {
|
||||||
noTypeInference = true;
|
|
||||||
needParentheses = true;
|
needParentheses = true;
|
||||||
} else {
|
} else {
|
||||||
showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.no.expression"));
|
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());
|
BindingContext bindingContext = AnalyzeSingleFileUtil.getContextForSingleFile((JetFile)expression.getContainingFile());
|
||||||
final JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); //can be null or error type
|
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) {
|
if (expressionType instanceof NamespaceType) {
|
||||||
showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.namespace.expression"));
|
showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.namespace.expression"));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ fun foo(c : Collection<String>){
|
|||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
fun foo(c : Collection<String>){
|
fun foo(c : Collection<String>){
|
||||||
val function: () -> Boolean = {it; false}
|
val function = {it; false}
|
||||||
c.filter(function)
|
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();
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testFunctionLiteralFromExpected() {
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
public void testIfCondition() {
|
public void testIfCondition() {
|
||||||
doTest();
|
doTest();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user