Adding parameter types for functions if necessary.
#KT-2637 in progress
This commit is contained in:
@@ -112,6 +112,14 @@ public class JetPsiFactory {
|
||||
return semicolon;
|
||||
}
|
||||
|
||||
//the pair contains the first and the last elements of a range
|
||||
@NotNull
|
||||
public static Pair<PsiElement, PsiElement> createWhitespaceAndArrow(Project project) {
|
||||
JetFunctionType functionType = (JetFunctionType) createType(project, "() -> Int").getTypeElement();
|
||||
assert functionType != null;
|
||||
return Pair.create(functionType.findElementAt(2), functionType.findElementAt(3));
|
||||
}
|
||||
|
||||
public static PsiElement createWhiteSpace(Project project) {
|
||||
return createWhiteSpace(project, " ");
|
||||
}
|
||||
|
||||
@@ -49,6 +49,10 @@ public class ErrorUtils {
|
||||
if (containsErrorType(function.getReturnType())) {
|
||||
return true;
|
||||
}
|
||||
ReceiverParameterDescriptor receiverParameter = function.getReceiverParameter();
|
||||
if (receiverParameter != null && containsErrorType(receiverParameter.getType())) {
|
||||
return true;
|
||||
}
|
||||
for (ValueParameterDescriptor parameter : function.getValueParameters()) {
|
||||
if (containsErrorType(parameter.getType())) {
|
||||
return true;
|
||||
|
||||
@@ -12,13 +12,16 @@ import com.intellij.openapi.editor.colors.EditorColors;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.wm.StatusBar;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.HelpID;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
@@ -27,7 +30,10 @@ import com.intellij.util.Function;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.diagnostics.AbstractDiagnosticFactory;
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
@@ -35,6 +41,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
|
||||
import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils;
|
||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.jet.plugin.JetLanguage;
|
||||
@@ -99,6 +106,7 @@ public class KotlinInlineLocalHandler extends InlineActionHandler {
|
||||
}
|
||||
|
||||
final String typeArgumentsForCall = getTypeArgumentsStringForCall(initializer);
|
||||
final String parametersForFunctionLiteral = getParametersForFunctionLiteral(initializer);
|
||||
|
||||
PsiReference[] referencesArray = references.toArray(references.toArray(new PsiReference[references.size()]));
|
||||
|
||||
@@ -150,12 +158,110 @@ public class KotlinInlineLocalHandler extends InlineActionHandler {
|
||||
if (typeArgumentsForCall != null) {
|
||||
addTypeArguments(typeArgumentsForCall, inlinedExpressions);
|
||||
}
|
||||
|
||||
if (parametersForFunctionLiteral != null) {
|
||||
addFunctionLiteralParameterTypes(parametersForFunctionLiteral, inlinedExpressions);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, RefactoringBundle.message("inline.command", name), null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getParametersForFunctionLiteral(JetExpression initializer) {
|
||||
JetFunctionLiteralExpression functionLiteralExpression = getFunctionLiteralExpression(initializer);
|
||||
if (functionLiteralExpression == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ResolveSession resolveSession = AnalyzerFacadeWithCache.getLazyResolveSession((JetFile) initializer.getContainingFile());
|
||||
BindingContext context = ResolveSessionUtils.resolveToExpression(resolveSession, initializer);
|
||||
SimpleFunctionDescriptor fun = context.get(BindingContext.FUNCTION, functionLiteralExpression.getFunctionLiteral());
|
||||
if (fun == null || ErrorUtils.containsErrorType(fun)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return StringUtil.join(fun.getValueParameters(), new Function<ValueParameterDescriptor, String>() {
|
||||
@Override
|
||||
public String fun(ValueParameterDescriptor descriptor) {
|
||||
return descriptor.getName() + ": " + DescriptorRenderer.TEXT.renderType(descriptor.getType());
|
||||
}
|
||||
}, ", ");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JetFunctionLiteralExpression getFunctionLiteralExpression(@NotNull JetExpression expression) {
|
||||
if (expression instanceof JetParenthesizedExpression) {
|
||||
JetExpression inner = ((JetParenthesizedExpression) expression).getExpression();
|
||||
return inner == null ? null : getFunctionLiteralExpression(inner);
|
||||
}
|
||||
if (expression instanceof JetFunctionLiteralExpression) {
|
||||
return (JetFunctionLiteralExpression) expression;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void addFunctionLiteralParameterTypes(@NotNull String parameters, @NotNull List<JetExpression> inlinedExpressions) {
|
||||
JetFile containingFile = (JetFile) inlinedExpressions.get(0).getContainingFile();
|
||||
List<JetFunctionLiteralExpression> functionsToAddParameters = Lists.newArrayList();
|
||||
|
||||
ResolveSession resolveSession = AnalyzerFacadeWithCache.getLazyResolveSession(containingFile);
|
||||
for (JetExpression inlinedExpression : inlinedExpressions) {
|
||||
JetFunctionLiteralExpression functionLiteralExpression = getFunctionLiteralExpression(inlinedExpression);
|
||||
assert functionLiteralExpression != null : "can't find function literal expression for " + inlinedExpression.getText();
|
||||
|
||||
if (needToAddParameterTypes(functionLiteralExpression, resolveSession)) {
|
||||
functionsToAddParameters.add(functionLiteralExpression);
|
||||
}
|
||||
}
|
||||
|
||||
for (JetFunctionLiteralExpression functionLiteralExpression : functionsToAddParameters) {
|
||||
JetFunctionLiteral functionLiteral = functionLiteralExpression.getFunctionLiteral();
|
||||
|
||||
JetParameterList currentParameterList = functionLiteral.getValueParameterList();
|
||||
JetParameterList newParameterList = JetPsiFactory.createParameterList(containingFile.getProject(), "(" + parameters + ")");
|
||||
if (currentParameterList != null) {
|
||||
currentParameterList.replace(newParameterList);
|
||||
}
|
||||
else {
|
||||
PsiElement openBraceElement = functionLiteral.getOpenBraceNode().getPsi();
|
||||
|
||||
PsiElement nextSibling = openBraceElement.getNextSibling();
|
||||
PsiElement whitespaceToAdd = nextSibling instanceof PsiWhiteSpace && nextSibling.getText().contains("\n")
|
||||
? nextSibling.copy() : null;
|
||||
|
||||
Pair<PsiElement, PsiElement> whitespaceAndArrow = JetPsiFactory.createWhitespaceAndArrow(containingFile.getProject());
|
||||
functionLiteral.addRangeAfter(whitespaceAndArrow.first, whitespaceAndArrow.second, openBraceElement);
|
||||
|
||||
functionLiteral.addAfter(newParameterList, openBraceElement);
|
||||
if (whitespaceToAdd != null) {
|
||||
functionLiteral.addAfter(whitespaceToAdd, openBraceElement);
|
||||
}
|
||||
}
|
||||
ReferenceToClassesShortening.compactReferenceToClasses(functionLiteralExpression.getValueParameters());
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean needToAddParameterTypes(
|
||||
@NotNull JetFunctionLiteralExpression functionLiteralExpression,
|
||||
@NotNull ResolveSession resolveSession
|
||||
) {
|
||||
JetFunctionLiteral functionLiteral = functionLiteralExpression.getFunctionLiteral();
|
||||
BindingContext context = ResolveSessionUtils.resolveToExpression(resolveSession, functionLiteralExpression);
|
||||
for (Diagnostic diagnostic : context.getDiagnostics()) {
|
||||
AbstractDiagnosticFactory factory = diagnostic.getFactory();
|
||||
PsiElement element = diagnostic.getPsiElement();
|
||||
boolean hasCantInferParameter = factory == Errors.CANNOT_INFER_PARAMETER_TYPE && element.getParent().getParent() == functionLiteral;
|
||||
boolean hasUnresolvedItOrThis = factory == Errors.UNRESOLVED_REFERENCE && element.getText().equals("it") &&
|
||||
PsiTreeUtil.getParentOfType(element, JetFunctionLiteral.class) == functionLiteral;
|
||||
if (hasCantInferParameter || hasUnresolvedItOrThis) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void addTypeArguments(@NotNull String typeArguments, @NotNull List<JetExpression> inlinedExpressions) {
|
||||
JetFile containingFile = (JetFile) inlinedExpressions.get(0).getContainingFile();
|
||||
List<JetCallExpression> callsToAddArguments = Lists.newArrayList();
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo() {
|
||||
val f: (Int) -> Int = { x -> x }
|
||||
val ff: (Int) -> Int = <caret>f
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fun foo() {
|
||||
val ff: (Int) -> Int = { x -> x }
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo() {
|
||||
val f = { x -> x }
|
||||
val ff = <caret>f
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fun foo() {
|
||||
val ff = { x -> x }
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo() {
|
||||
val f: (Int) -> Int = { it }
|
||||
val ff = <caret>f
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fun foo() {
|
||||
val ff = {(it: Int) -> it }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
fun foo() {
|
||||
val f: (Int) -> Int = {
|
||||
it
|
||||
}
|
||||
val ff = <caret>f
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
fun foo() {
|
||||
val ff = {
|
||||
(it: Int) ->
|
||||
it
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo() {
|
||||
val f: (Int) -> Int = (({ x -> x }))
|
||||
val ff = <caret>f
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fun foo() {
|
||||
val ff = (({(x: Int) -> x }))
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo() {
|
||||
val f: (Int) -> Int = { x -> x }
|
||||
val ff = <caret>f
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fun foo() {
|
||||
val ff = {(x: Int) -> x }
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo() {
|
||||
val f = { 1 }
|
||||
val ff = <caret>f
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fun foo() {
|
||||
val ff = { 1 }
|
||||
}
|
||||
@@ -31,7 +31,7 @@ import org.jetbrains.jet.plugin.refactoring.inline.AbstractInlineTest;
|
||||
/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("idea/testData/refactoring/inline")
|
||||
@InnerTestClasses({InlineTestGenerated.AddParenthesis.class, InlineTestGenerated.ExplicateTypeArgument.class})
|
||||
@InnerTestClasses({InlineTestGenerated.AddParenthesis.class, InlineTestGenerated.ExplicateParameterTypes.class, InlineTestGenerated.ExplicateTypeArgument.class})
|
||||
public class InlineTestGenerated extends AbstractInlineTest {
|
||||
public void testAllFilesPresentInInline() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/refactoring/inline"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
@@ -255,6 +255,49 @@ public class InlineTestGenerated extends AbstractInlineTest {
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/refactoring/inline/explicateParameterTypes")
|
||||
public static class ExplicateParameterTypes extends AbstractInlineTest {
|
||||
public void testAllFilesPresentInExplicateParameterTypes() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/refactoring/inline/explicateParameterTypes"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("EnoughDontExplicate.kt")
|
||||
public void testEnoughDontExplicate() throws Exception {
|
||||
doTest("idea/testData/refactoring/inline/explicateParameterTypes/EnoughDontExplicate.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ErrorTypes.kt")
|
||||
public void testErrorTypes() throws Exception {
|
||||
doTest("idea/testData/refactoring/inline/explicateParameterTypes/ErrorTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("It.kt")
|
||||
public void testIt() throws Exception {
|
||||
doTest("idea/testData/refactoring/inline/explicateParameterTypes/It.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ItMultiLine.kt")
|
||||
public void testItMultiLine() throws Exception {
|
||||
doTest("idea/testData/refactoring/inline/explicateParameterTypes/ItMultiLine.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("Parenthesized.kt")
|
||||
public void testParenthesized() throws Exception {
|
||||
doTest("idea/testData/refactoring/inline/explicateParameterTypes/Parenthesized.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("Simplest.kt")
|
||||
public void testSimplest() throws Exception {
|
||||
doTest("idea/testData/refactoring/inline/explicateParameterTypes/Simplest.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("TrivialDontExplicate.kt")
|
||||
public void testTrivialDontExplicate() throws Exception {
|
||||
doTest("idea/testData/refactoring/inline/explicateParameterTypes/TrivialDontExplicate.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/refactoring/inline/explicateTypeArgument")
|
||||
public static class ExplicateTypeArgument extends AbstractInlineTest {
|
||||
public void testAllFilesPresentInExplicateTypeArgument() throws Exception {
|
||||
@@ -312,6 +355,7 @@ public class InlineTestGenerated extends AbstractInlineTest {
|
||||
TestSuite suite = new TestSuite("InlineTestGenerated");
|
||||
suite.addTestSuite(InlineTestGenerated.class);
|
||||
suite.addTestSuite(AddParenthesis.class);
|
||||
suite.addTestSuite(ExplicateParameterTypes.class);
|
||||
suite.addTestSuite(ExplicateTypeArgument.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user