diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index aad818c3785..4f59ca5d8ca 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -358,7 +358,7 @@ public interface Errors { // Multi-declarations DiagnosticFactory0 INITIALIZER_REQUIRED_FOR_MULTIDECLARATION = DiagnosticFactory0.create(ERROR, DEFAULT); - DiagnosticFactory1 COMPONENT_FUNCTION_MISSING = DiagnosticFactory1.create(ERROR, DEFAULT); + DiagnosticFactory2 COMPONENT_FUNCTION_MISSING = DiagnosticFactory2.create(ERROR, DEFAULT); DiagnosticFactory2>> COMPONENT_FUNCTION_AMBIGUITY = DiagnosticFactory2.create(ERROR, DEFAULT); DiagnosticFactory3 COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH = DiagnosticFactory3.create(ERROR, DEFAULT); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index 409d7dfdf1b..6cf84bf8dfc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -113,7 +113,7 @@ public class DefaultErrorMessages { MAP.put(VARIABLE_WITH_NO_TYPE_NO_INITIALIZER, "This variable must either have a type annotation or be initialized"); MAP.put(INITIALIZER_REQUIRED_FOR_MULTIDECLARATION, "Initializer required for multi-declaration"); - MAP.put(COMPONENT_FUNCTION_MISSING, "Multi-declaration initializer must have a ''{0}()'' function", TO_STRING); + MAP.put(COMPONENT_FUNCTION_MISSING, "Multi-declaration initializer of type {1} must have a ''{0}()'' function", TO_STRING, RENDER_TYPE); MAP.put(COMPONENT_FUNCTION_AMBIGUITY, "Function ''{0}()'' is ambiguous for this expression: {1}", TO_STRING, AMBIGUOUS_CALLS); MAP.put(COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH, "''{0}()'' function returns ''{1}'', but ''{2}'' is expected", TO_STRING, RENDER_TYPE, RENDER_TYPE); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java index 1e1d6e9f60d..04ae58719c1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java @@ -417,7 +417,7 @@ public class ExpressionTypingUtils { context.trace.report(COMPONENT_FUNCTION_AMBIGUITY.on(reportErrorsOn, componentName, results.getResultingCalls())); } else { - context.trace.report(COMPONENT_FUNCTION_MISSING.on(reportErrorsOn, componentName)); + context.trace.report(COMPONENT_FUNCTION_MISSING.on(reportErrorsOn, componentName, receiver.getType())); } if (componentType == null) { componentType = ErrorUtils.createErrorType(componentName + "() return type"); diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/CreateFunctionFromUsageFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/CreateFunctionFromUsageFix.java index 4baff4383be..5bc985a1b3a 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/CreateFunctionFromUsageFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/CreateFunctionFromUsageFix.java @@ -51,9 +51,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor; -import org.jetbrains.jet.lang.diagnostics.Diagnostic; -import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters1; -import org.jetbrains.jet.lang.diagnostics.Errors; +import org.jetbrains.jet.lang.diagnostics.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; @@ -1313,7 +1311,10 @@ public class CreateFunctionFromUsageFix extends CreateFromUsageFixBase { JetForExpression forExpr = QuickFixUtil.getParentElementOfType(diagnostic, JetForExpression.class); if (forExpr == null) return null; JetExpression variableExpr = forExpr.getLoopParameter(); - if (variableExpr == null) return null; + if (variableExpr == null) { + variableExpr = forExpr.getMultiParameter(); + if (variableExpr == null) return null; + } TypeOrExpressionThereof returnType = new TypeOrExpressionThereof(variableExpr, Variance.OUT_VARIANCE); return new CreateFunctionFromUsageFix(forExpr, ownerType, "next", returnType, new ArrayList()); } @@ -1335,7 +1336,10 @@ public class CreateFunctionFromUsageFix extends CreateFromUsageFixBase { JetExpression iterableExpr = forExpr.getLoopRange(); if (iterableExpr == null) return null; JetExpression variableExpr = forExpr.getLoopParameter(); - if (variableExpr == null) return null; + if (variableExpr == null) { + variableExpr = forExpr.getMultiParameter(); + if (variableExpr == null) return null; + } TypeOrExpressionThereof iterableType = new TypeOrExpressionThereof(iterableExpr, Variance.IN_VARIANCE); JetType returnJetType = KotlinBuiltIns.getInstance().getIterator().getDefaultType(); @@ -1359,25 +1363,33 @@ public class CreateFunctionFromUsageFix extends CreateFromUsageFixBase { @Nullable @Override public IntentionAction createAction(Diagnostic diagnostic) { - JetMultiDeclaration multiDeclaration = QuickFixUtil.getParentElementOfType(diagnostic, JetMultiDeclaration.class); - if (multiDeclaration == null) return null; - List entries = multiDeclaration.getEntries(); - assert diagnostic.getFactory() == Errors.COMPONENT_FUNCTION_MISSING; @SuppressWarnings("unchecked") - DiagnosticWithParameters1 diagnosticWithParameters = - (DiagnosticWithParameters1) diagnostic; + DiagnosticWithParameters2 diagnosticWithParameters = + (DiagnosticWithParameters2) diagnostic; Name name = diagnosticWithParameters.getA(); Matcher componentNumberMatcher = COMPONENT_FUNCTION_PATTERN.matcher(name.getIdentifier()); if (!componentNumberMatcher.matches()) return null; String componentNumberString = componentNumberMatcher.group(1); int componentNumber = Integer.decode(componentNumberString) - 1; + JetMultiDeclaration multiDeclaration = QuickFixUtil.getParentElementOfType(diagnostic, JetMultiDeclaration.class); + TypeOrExpressionThereof ownerType; + if (multiDeclaration == null) { // if it's not a multi-declaration, must be a multi parameter in a for-loop + JetForExpression forExpr = QuickFixUtil.getParentElementOfType(diagnostic, JetForExpression.class); + if (forExpr == null) return null; + multiDeclaration = forExpr.getMultiParameter(); + if (multiDeclaration == null) return null; + ownerType = new TypeOrExpressionThereof(diagnosticWithParameters.getB(), Variance.IN_VARIANCE); + } else { + JetExpression rhs = multiDeclaration.getInitializer(); + if (rhs == null) return null; + ownerType = new TypeOrExpressionThereof(rhs, Variance.IN_VARIANCE); + } + List entries = multiDeclaration.getEntries(); + JetMultiDeclarationEntry entry = entries.get(componentNumber); TypeOrExpressionThereof returnType = new TypeOrExpressionThereof(entry, Variance.OUT_VARIANCE); - JetExpression rhs = multiDeclaration.getInitializer(); - if (rhs == null) return null; - TypeOrExpressionThereof ownerType = new TypeOrExpressionThereof(rhs, Variance.IN_VARIANCE); return new CreateFunctionFromUsageFix(multiDeclaration, ownerType, name.getIdentifier(), returnType, new ArrayList()); } diff --git a/idea/testData/quickfix/createFromUsage/component/afterCreateComponentFromUsage3.kt b/idea/testData/quickfix/createFromUsage/component/afterCreateComponentFromUsage3.kt new file mode 100644 index 00000000000..ec065712113 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/component/afterCreateComponentFromUsage3.kt @@ -0,0 +1,21 @@ +// "Create function 'component2' from usage" "true" +class FooIterator { + fun hasNext(): Boolean { return false } + fun next(): Any { + throw UnsupportedOperationException("not implemented") + } +} +class Foo { + fun iterator(): FooIterator { + throw UnsupportedOperationException("not implemented") + } +} +fun Any.component1(): Int { + return 0 +} +fun foo() { + for ((i: Int, j: Int) in Foo()) { } +} +fun Any.component2(): Int { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/component/beforeCreateComponentFromUsage3.kt b/idea/testData/quickfix/createFromUsage/component/beforeCreateComponentFromUsage3.kt new file mode 100644 index 00000000000..e14353788b6 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/component/beforeCreateComponentFromUsage3.kt @@ -0,0 +1,18 @@ +// "Create function 'component2' from usage" "true" +class FooIterator { + fun hasNext(): Boolean { return false } + fun next(): Any { + throw UnsupportedOperationException("not implemented") + } +} +class Foo { + fun iterator(): FooIterator { + throw UnsupportedOperationException("not implemented") + } +} +fun Any.component1(): Int { + return 0 +} +fun foo() { + for ((i: Int, j: Int) in Foo()) { } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/iterator/afterCreateIteratorFromUsage3.kt b/idea/testData/quickfix/createFromUsage/iterator/afterCreateIteratorFromUsage3.kt new file mode 100644 index 00000000000..3c7b5edc152 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/iterator/afterCreateIteratorFromUsage3.kt @@ -0,0 +1,21 @@ +// "Create function 'next' from usage" "true" +class FooIterator { + fun hasNext(): Boolean { return false } + fun next(): Any { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} +class Foo { + fun iterator(): FooIterator { + throw UnsupportedOperationException("not implemented") + } +} +fun Any.component1(): Int { + return 0 +} +fun Any.component2(): Int { + return 0 +} +fun foo() { + for ((i: Int, j: Int) in Foo()) { } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/iterator/beforeCreateIteratorFromUsage3.kt b/idea/testData/quickfix/createFromUsage/iterator/beforeCreateIteratorFromUsage3.kt new file mode 100644 index 00000000000..7f57c5cc39b --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/iterator/beforeCreateIteratorFromUsage3.kt @@ -0,0 +1,18 @@ +// "Create function 'next' from usage" "true" +class FooIterator { + fun hasNext(): Boolean { return false } +} +class Foo { + fun iterator(): FooIterator { + throw UnsupportedOperationException("not implemented") + } +} +fun Any.component1(): Int { + return 0 +} +fun Any.component2(): Int { + return 0 +} +fun foo() { + for ((i: Int, j: Int) in Foo()) { } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java index bf4b20b7aeb..9675a9607ac 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java @@ -452,6 +452,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest("idea/testData/quickfix/createFromUsage/component/beforeCreateComponentFromUsage2.kt"); } + @TestMetadata("beforeCreateComponentFromUsage3.kt") + public void testCreateComponentFromUsage3() throws Exception { + doTest("idea/testData/quickfix/createFromUsage/component/beforeCreateComponentFromUsage3.kt"); + } + } @TestMetadata("idea/testData/quickfix/createFromUsage/get") @@ -561,6 +566,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest("idea/testData/quickfix/createFromUsage/iterator/beforeCreateIteratorFromUsage2.kt"); } + @TestMetadata("beforeCreateIteratorFromUsage3.kt") + public void testCreateIteratorFromUsage3() throws Exception { + doTest("idea/testData/quickfix/createFromUsage/iterator/beforeCreateIteratorFromUsage3.kt"); + } + } @TestMetadata("idea/testData/quickfix/createFromUsage/next")