diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 222c921b0e4e3..b310017ce3958 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1902,6 +1902,20 @@ public StackValue visitCallExpression(@NotNull JetCallExpression expression, Sta JetExpression callee = expression.getCalleeExpression(); assert callee != null; + DottedCallInfo dottedCallInfo = bindingContext.get(BindingContext.DOTTED_CALL_INFO, expression); + if (dottedCallInfo != null) { + ResolvedCall resolvedDotCall = dottedCallInfo.getResolvedCall(); + FunctionDescriptor dotFunDescriptor = accessibleFunctionDescriptor(resolvedDotCall.getResultingDescriptor()); + + JetType dotType = dotFunDescriptor.getReturnType(); + assert dotType != null : "can't resolve type of dot operation: " + dotFunDescriptor; + + StackValue newReceiver = invokeFunction(dottedCallInfo.getCall(), receiver, resolvedDotCall); + if (!KotlinBuiltIns.getInstance().isUnit(dotType)) { + receiver = newReceiver; + } + } + ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, callee); if (resolvedCall == null) { throw new CompilationException("Cannot resolve: " + callee.getText(), null, expression); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 50779064f4a29..51a2ea91dea80 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.CompileTimeConstantUtils; +import org.jetbrains.jet.lang.resolve.calls.model.DottedCallInfo; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument; import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; @@ -784,6 +785,11 @@ public void visitQualifiedExpressionVoid(@NotNull JetQualifiedExpression express generateInstructions(selectorExpression, NOT_IN_CONDITION); + DottedCallInfo dottedCallInfo = trace.get(BindingContext.DOTTED_CALL_INFO, selectorExpression); + if (dottedCallInfo != null) { + generateInstructions((JetCallExpression) dottedCallInfo.getCall().getCallElement(), NOT_IN_CONDITION); + } + // receiver was generated for resolvedCall JetExpression calleeExpression = JetPsiUtil.getCalleeExpressionIfAny(selectorExpression); if (calleeExpression == null || getResolvedCall(calleeExpression) == null) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 065d8a79300e1..e3e9986f0493f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -28,6 +28,7 @@ import org.jetbrains.jet.lang.resolve.calls.TailRecursionKind; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemCompleter; +import org.jetbrains.jet.lang.resolve.calls.model.DottedCallInfo; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.name.FqName; @@ -79,6 +80,7 @@ public ImmutableMap getSliceContents(@NotNull ReadOnlySlice s WritableSlice TYPE = Slices.createSimpleSlice(); WritableSlice EXPRESSION_TYPE = new BasicWritableSlice(DO_NOTHING); + WritableSlice DOTTED_EXPRESSION_TYPE = new BasicWritableSlice(DO_NOTHING); WritableSlice EXPECTED_EXPRESSION_TYPE = new BasicWritableSlice(DO_NOTHING); WritableSlice EXPRESSION_DATA_FLOW_INFO = new BasicWritableSlice(DO_NOTHING); WritableSlice DATAFLOW_INFO_AFTER_CONDITION = Slices.createSimpleSlice(); @@ -92,6 +94,8 @@ public ImmutableMap getSliceContents(@NotNull ReadOnlySlice s WritableSlice CONSTRAINT_SYSTEM_COMPLETER = new BasicWritableSlice(DO_NOTHING); WritableSlice CALL = new BasicWritableSlice(DO_NOTHING); + WritableSlice DOTTED_CALL_INFO = new BasicWritableSlice(DO_NOTHING); + @KotlinSignature("val AMBIGUOUS_REFERENCE_TARGET: WritableSlice>") WritableSlice> AMBIGUOUS_REFERENCE_TARGET = new BasicWritableSlice>(DO_NOTHING); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java index 2b35a885b974e..6c16561b0af48 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java @@ -32,10 +32,10 @@ import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode; import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext; import org.jetbrains.jet.lang.resolve.calls.context.TemporaryTraceAndCache; +import org.jetbrains.jet.lang.resolve.calls.model.DottedCallInfo; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; -import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil; import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; @@ -451,6 +451,52 @@ public JetTypeInfo getQualifiedExpressionTypeInfo( context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo()); + if (PsiTreeUtil.getParentOfType(expression, JetAnnotationEntry.class) == null) { + TemporaryTraceAndCache temporaryForDotOperation = TemporaryTraceAndCache.create( + context, "trace to check dot operation", expression + ); + + JetCallExpression fakeOperation = (JetCallExpression) JetPsiFactory.createExpression(expression.getProject(), "dot()"); + Call dotCall = CallMaker.makeCall( + fakeOperation, + new ExpressionReceiver(receiverExpression, receiverType), + null, + fakeOperation.getCalleeExpression(), + Collections.emptyList() + ); + OverloadResolutionResults dotOperationDescriptors = + expressionTypingServices.getCallResolver().resolveCallWithGivenName( + context.replaceTraceAndCache(temporaryForDotOperation), + dotCall, + fakeOperation, Name.identifier("dot") + ); + JetType dotOperationType = + OverloadResolutionResultsUtil.getResultingType(dotOperationDescriptors, context.contextDependency); + + if (dotOperationDescriptors.isSingleResult() && dotOperationType != null) { + ResolvedCall resolvedDotCall = dotOperationDescriptors.getResultingCall(); + ((ResolvedCallWithTrace) resolvedDotCall).markCallAsCompleted(); + + DottedCallInfo dottedCallInfo = new DottedCallInfo(dotCall, resolvedDotCall); + + context.trace.record(DOTTED_EXPRESSION_TYPE, receiverExpression, dotOperationType); + context.trace.record(DOTTED_CALL_INFO, selectorExpression, dottedCallInfo); + context.trace.record(RESOLVED_CALL, dotCall.getCalleeExpression(), resolvedDotCall); + + if (!KotlinBuiltIns.getInstance().isUnit(dotOperationType)) { + receiverType = dotOperationType; + context = context.replaceDataFlowInfo(resolvedDotCall.getDataFlowInfoForArguments().getResultInfo()); + } + } + else if (dotOperationDescriptors.isAmbiguity()) { + context.trace.report( + OVERLOAD_RESOLUTION_AMBIGUITY.on( + expression.getOperationTokenNode().getPsi(), dotOperationDescriptors.getResultingCalls() + ) + ); + } + } + JetTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo( new ExpressionReceiver(receiverExpression, receiverType), expression.getOperationTokenNode(), selectorExpression, context); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/model/DottedCallInfo.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/model/DottedCallInfo.kt new file mode 100644 index 0000000000000..f6d22be3b6689 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/model/DottedCallInfo.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.calls.model + +import org.jetbrains.jet.lang.psi.Call +import org.jetbrains.jet.lang.descriptors.CallableDescriptor +import org.jetbrains.jet.lang.types.JetType +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor + +class DottedCallInfo(val call: Call, val resolvedCall: ResolvedCall) diff --git a/compiler/testData/cfg/basic/humbleSimplicityOfDots.instructions b/compiler/testData/cfg/basic/humbleSimplicityOfDots.instructions new file mode 100644 index 0000000000000..8f7d89b64e540 --- /dev/null +++ b/compiler/testData/cfg/basic/humbleSimplicityOfDots.instructions @@ -0,0 +1,124 @@ +== dot == +fun Int.dot(): Int { + return this + 1 +} +--------------------- +L0: + 1 + 2 mark({ return this + 1 }) + mark(this + 1) + r(this) + r(1) + call(+, plus) + ret(*) L1 +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== dot == +fun String?.dot(): String = this ?: "" +--------------------- +L0: + 1 + r(this) + jt(L2) NEXT:[mark(""), ] + mark("") + r("") +L1: +L2: + NEXT:[] PREV:[jt(L2), r("")] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== i == +fun i(): Int? = null +--------------------- +L0: + 1 + r(null) +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== s == +fun s(): String? = null +--------------------- +L0: + 1 + r(null) +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== f == +fun f() : Unit { + 2.toLong() + 3.equals(4) + i()?.toLong() + + "test".length + s().length() +} +--------------------- +L0: + 1 + 2 mark({ 2.toLong() 3.equals(4) i()?.toLong() "test".length s().length() }) + mark(2.toLong()) + mark(toLong()) + r(2) + call(toLong, toLong) + mark(dot()) + r(2) + call(dot, dot) + mark(3.equals(4)) + mark(equals(4)) + r(3) + r(4) + call(equals, equals) + mark(dot()) + r(3) + call(dot, dot) + mark(i()?.toLong()) + mark(toLong()) + mark(i()) + call(i, i) + call(toLong, toLong) + mark(dot()) + mark(i()) + call(i, i) + call(dot, dot) + mark("test".length) + mark("test") + r("test") + r(length) + mark(dot()) + mark("test") + r("test") + call(dot, dot) + mark(s().length()) + mark(length()) + mark(s()) + call(s, s) + r(length) + mark(dot()) + mark(s()) + call(s, s) + call(dot, dot) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/basic/humbleSimplicityOfDots.kt b/compiler/testData/cfg/basic/humbleSimplicityOfDots.kt new file mode 100644 index 0000000000000..d86bb86f056b6 --- /dev/null +++ b/compiler/testData/cfg/basic/humbleSimplicityOfDots.kt @@ -0,0 +1,18 @@ +fun Int.dot(): Int { + return this + 1 +} + +fun String?.dot(): String = this ?: "" + +fun i(): Int? = null + +fun s(): String? = null + +fun f() : Unit { + 2.toLong() + 3.equals(4) + i()?.toLong() + + "test".length + s().length() +} diff --git a/compiler/testData/codegen/box/dot/inTheVoidOfDots.kt b/compiler/testData/codegen/box/dot/inTheVoidOfDots.kt new file mode 100644 index 0000000000000..a96cd891f621b --- /dev/null +++ b/compiler/testData/codegen/box/dot/inTheVoidOfDots.kt @@ -0,0 +1,22 @@ +class Foo { + fun foo(): String { + return "O" + } +} + +class Bar { + fun bar(): String { + return "" + } +} + +var t: String = "" + +fun Foo.dot() { + t = "K" +} + +fun box(): String { + val f: Foo = Foo() + return f.foo() + t +} diff --git a/compiler/testData/codegen/box/dot/onlyDotCanKeepYouFromFailure.kt b/compiler/testData/codegen/box/dot/onlyDotCanKeepYouFromFailure.kt new file mode 100644 index 0000000000000..f9b599ea1bf96 --- /dev/null +++ b/compiler/testData/codegen/box/dot/onlyDotCanKeepYouFromFailure.kt @@ -0,0 +1,23 @@ +class Foo { + fun foo(): String { + return "FAIL" + } +} + +class Bar { + fun bar(): String { + return "O" + } +} + +var t: String = "" + +fun Foo.dot(): Bar { + t = "K" + return Bar() +} + +fun box(): String { + val f: Foo = Foo() + return f.bar() + t +} diff --git a/compiler/testData/diagnostics/tests/dataFlow/nothingLikeDot.kt b/compiler/testData/diagnostics/tests/dataFlow/nothingLikeDot.kt new file mode 100644 index 0000000000000..60c8d53569cf3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataFlow/nothingLikeDot.kt @@ -0,0 +1,8 @@ +fun Any?.dot(): Nothing { + throw RuntimeException() +} + +fun test(): String { + val s: String? = "" + return s.dot() +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java index d509cddf1d445..e81f0eb1c9325 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java @@ -86,6 +86,11 @@ public void testEmptyFunction() throws Exception { doTest("compiler/testData/cfg/basic/EmptyFunction.kt"); } + @TestMetadata("humbleSimplicityOfDots.kt") + public void testHumbleSimplicityOfDots() throws Exception { + doTest("compiler/testData/cfg/basic/humbleSimplicityOfDots.kt"); + } + @TestMetadata("ShortFunction.kt") public void testShortFunction() throws Exception { doTest("compiler/testData/cfg/basic/ShortFunction.kt"); diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 9a3fa94a8366f..3e220de460ff9 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1957,6 +1957,11 @@ public void testIsExpression() throws Exception { doTest("compiler/testData/diagnostics/tests/dataFlow/IsExpression.kt"); } + @TestMetadata("nothingLikeDot.kt") + public void testNothingLikeDot() throws Exception { + doTest("compiler/testData/diagnostics/tests/dataFlow/nothingLikeDot.kt"); + } + @TestMetadata("WhenSubject.kt") public void testWhenSubject() throws Exception { doTest("compiler/testData/diagnostics/tests/dataFlow/WhenSubject.kt"); diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index a198a6914a9f9..c106f262c8003 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -31,7 +31,7 @@ /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("compiler/testData/codegen/box") -@InnerTestClasses({BlackBoxCodegenTestGenerated.Arrays.class, BlackBoxCodegenTestGenerated.BinaryOp.class, BlackBoxCodegenTestGenerated.Bridges.class, BlackBoxCodegenTestGenerated.BuiltinStubMethods.class, BlackBoxCodegenTestGenerated.CallableReference.class, BlackBoxCodegenTestGenerated.Casts.class, BlackBoxCodegenTestGenerated.Classes.class, BlackBoxCodegenTestGenerated.Closures.class, BlackBoxCodegenTestGenerated.Constants.class, BlackBoxCodegenTestGenerated.ControlStructures.class, BlackBoxCodegenTestGenerated.DefaultArguments.class, BlackBoxCodegenTestGenerated.DelegatedProperty.class, BlackBoxCodegenTestGenerated.Elvis.class, BlackBoxCodegenTestGenerated.Enum.class, BlackBoxCodegenTestGenerated.ExclExcl.class, BlackBoxCodegenTestGenerated.ExtensionFunctions.class, BlackBoxCodegenTestGenerated.ExtensionProperties.class, BlackBoxCodegenTestGenerated.FakeOverride.class, BlackBoxCodegenTestGenerated.FieldRename.class, BlackBoxCodegenTestGenerated.Finally.class, BlackBoxCodegenTestGenerated.Functions.class, BlackBoxCodegenTestGenerated.InnerNested.class, BlackBoxCodegenTestGenerated.Instructions.class, BlackBoxCodegenTestGenerated.Intrinsics.class, BlackBoxCodegenTestGenerated.Labels.class, BlackBoxCodegenTestGenerated.LocalClasses.class, BlackBoxCodegenTestGenerated.MultiDecl.class, BlackBoxCodegenTestGenerated.Objects.class, BlackBoxCodegenTestGenerated.OperatorConventions.class, BlackBoxCodegenTestGenerated.Package.class, BlackBoxCodegenTestGenerated.PrimitiveTypes.class, BlackBoxCodegenTestGenerated.Properties.class, BlackBoxCodegenTestGenerated.Reflection.class, BlackBoxCodegenTestGenerated.SafeCall.class, BlackBoxCodegenTestGenerated.SamConstructors.class, BlackBoxCodegenTestGenerated.Strings.class, BlackBoxCodegenTestGenerated.Super.class, BlackBoxCodegenTestGenerated.ToArray.class, BlackBoxCodegenTestGenerated.Traits.class, BlackBoxCodegenTestGenerated.TypeInfo.class, BlackBoxCodegenTestGenerated.TypeMapping.class, BlackBoxCodegenTestGenerated.UnaryOp.class, BlackBoxCodegenTestGenerated.Unit.class, BlackBoxCodegenTestGenerated.Vararg.class, BlackBoxCodegenTestGenerated.When.class}) +@InnerTestClasses({BlackBoxCodegenTestGenerated.Arrays.class, BlackBoxCodegenTestGenerated.BinaryOp.class, BlackBoxCodegenTestGenerated.Bridges.class, BlackBoxCodegenTestGenerated.BuiltinStubMethods.class, BlackBoxCodegenTestGenerated.CallableReference.class, BlackBoxCodegenTestGenerated.Casts.class, BlackBoxCodegenTestGenerated.Classes.class, BlackBoxCodegenTestGenerated.Closures.class, BlackBoxCodegenTestGenerated.Constants.class, BlackBoxCodegenTestGenerated.ControlStructures.class, BlackBoxCodegenTestGenerated.DefaultArguments.class, BlackBoxCodegenTestGenerated.DelegatedProperty.class, BlackBoxCodegenTestGenerated.Dot.class, BlackBoxCodegenTestGenerated.Elvis.class, BlackBoxCodegenTestGenerated.Enum.class, BlackBoxCodegenTestGenerated.ExclExcl.class, BlackBoxCodegenTestGenerated.ExtensionFunctions.class, BlackBoxCodegenTestGenerated.ExtensionProperties.class, BlackBoxCodegenTestGenerated.FakeOverride.class, BlackBoxCodegenTestGenerated.FieldRename.class, BlackBoxCodegenTestGenerated.Finally.class, BlackBoxCodegenTestGenerated.Functions.class, BlackBoxCodegenTestGenerated.InnerNested.class, BlackBoxCodegenTestGenerated.Instructions.class, BlackBoxCodegenTestGenerated.Intrinsics.class, BlackBoxCodegenTestGenerated.Labels.class, BlackBoxCodegenTestGenerated.LocalClasses.class, BlackBoxCodegenTestGenerated.MultiDecl.class, BlackBoxCodegenTestGenerated.Objects.class, BlackBoxCodegenTestGenerated.OperatorConventions.class, BlackBoxCodegenTestGenerated.Package.class, BlackBoxCodegenTestGenerated.PrimitiveTypes.class, BlackBoxCodegenTestGenerated.Properties.class, BlackBoxCodegenTestGenerated.Reflection.class, BlackBoxCodegenTestGenerated.SafeCall.class, BlackBoxCodegenTestGenerated.SamConstructors.class, BlackBoxCodegenTestGenerated.Strings.class, BlackBoxCodegenTestGenerated.Super.class, BlackBoxCodegenTestGenerated.ToArray.class, BlackBoxCodegenTestGenerated.Traits.class, BlackBoxCodegenTestGenerated.TypeInfo.class, BlackBoxCodegenTestGenerated.TypeMapping.class, BlackBoxCodegenTestGenerated.UnaryOp.class, BlackBoxCodegenTestGenerated.Unit.class, BlackBoxCodegenTestGenerated.Vararg.class, BlackBoxCodegenTestGenerated.When.class}) public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInBox() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/box"), Pattern.compile("^(.+)\\.kt$"), true); @@ -2246,6 +2246,24 @@ public void testVararg() throws Exception { } + @TestMetadata("compiler/testData/codegen/box/dot") + public static class Dot extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInDot() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/box/dot"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("inTheVoidOfDots.kt") + public void testInTheVoidOfDots() throws Exception { + doTest("compiler/testData/codegen/box/dot/inTheVoidOfDots.kt"); + } + + @TestMetadata("onlyDotCanKeepYouFromFailure.kt") + public void testOnlyDotCanKeepYouFromFailure() throws Exception { + doTest("compiler/testData/codegen/box/dot/onlyDotCanKeepYouFromFailure.kt"); + } + + } + @TestMetadata("compiler/testData/codegen/box/elvis") public static class Elvis extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInElvis() throws Exception { @@ -5485,6 +5503,7 @@ public static Test suite() { suite.addTestSuite(ControlStructures.class); suite.addTest(DefaultArguments.innerSuite()); suite.addTestSuite(DelegatedProperty.class); + suite.addTestSuite(Dot.class); suite.addTestSuite(Elvis.class); suite.addTestSuite(Enum.class); suite.addTestSuite(ExclExcl.class); diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.java index d202f6d75e3d9..5450c7d8d4af2 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.java @@ -57,7 +57,10 @@ public static Collection getReferenceVariants( if (receiverExpression != null && inPositionForCompletionWithReceiver) { // Process as call expression JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression); - JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression); + JetType expressionType = context.get(BindingContext.DOTTED_EXPRESSION_TYPE, receiverExpression); + if (expressionType == null) { + expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression); + } if (expressionType != null && resolutionScope != null && !expressionType.isError()) { if (!(expressionType instanceof PackageType)) { diff --git a/idea/testData/completion/basic/common/javaDotNet.kt b/idea/testData/completion/basic/common/javaDotNet.kt new file mode 100644 index 0000000000000..1034f55d853b3 --- /dev/null +++ b/idea/testData/completion/basic/common/javaDotNet.kt @@ -0,0 +1,15 @@ +class Java() { + fun oracleRulezzz() +} + +class DotNet { + fun microsoftRulezzz() +} + +fun Java.dot(): DotNet = DotNet() + +fun test() { + Java(). +} + +// EXIST: microsoftRulezzz \ No newline at end of file diff --git a/idea/testData/completion/basic/common/onlyDotSurvives.kt b/idea/testData/completion/basic/common/onlyDotSurvives.kt new file mode 100644 index 0000000000000..ec8d7fff93073 --- /dev/null +++ b/idea/testData/completion/basic/common/onlyDotSurvives.kt @@ -0,0 +1,10 @@ +fun String?.dot(): Nothing { + throw RuntimeException() +} + +fun box(): String { + val s: String? = "" + return s. +} + +// EXIST: dot \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/completion/JSBasicCompletionTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/JSBasicCompletionTestGenerated.java index 6d0d47a214030..964bef64df183 100644 --- a/idea/tests/org/jetbrains/jet/completion/JSBasicCompletionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/JSBasicCompletionTestGenerated.java @@ -309,6 +309,11 @@ public void testInTypeAnnotation() throws Exception { doTest("idea/testData/completion/basic/common/InTypeAnnotation.kt"); } + @TestMetadata("javaDotNet.kt") + public void testJavaDotNet() throws Exception { + doTest("idea/testData/completion/basic/common/javaDotNet.kt"); + } + @TestMetadata("JavaPackage.kt") public void testJavaPackage() throws Exception { doTest("idea/testData/completion/basic/common/JavaPackage.kt"); @@ -374,6 +379,11 @@ public void testObjectRedeclaration2() throws Exception { doTest("idea/testData/completion/basic/common/ObjectRedeclaration2.kt"); } + @TestMetadata("onlyDotSurvives.kt") + public void testOnlyDotSurvives() throws Exception { + doTest("idea/testData/completion/basic/common/onlyDotSurvives.kt"); + } + @TestMetadata("OnlyScopedClassesWithoutExplicit.kt") public void testOnlyScopedClassesWithoutExplicit() throws Exception { doTest("idea/testData/completion/basic/common/OnlyScopedClassesWithoutExplicit.kt"); diff --git a/idea/tests/org/jetbrains/jet/completion/JvmBasicCompletionTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/JvmBasicCompletionTestGenerated.java index e88eef2b8eed2..a6ebf1bff9f3f 100644 --- a/idea/tests/org/jetbrains/jet/completion/JvmBasicCompletionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/JvmBasicCompletionTestGenerated.java @@ -309,6 +309,11 @@ public void testInTypeAnnotation() throws Exception { doTest("idea/testData/completion/basic/common/InTypeAnnotation.kt"); } + @TestMetadata("javaDotNet.kt") + public void testJavaDotNet() throws Exception { + doTest("idea/testData/completion/basic/common/javaDotNet.kt"); + } + @TestMetadata("JavaPackage.kt") public void testJavaPackage() throws Exception { doTest("idea/testData/completion/basic/common/JavaPackage.kt"); @@ -374,6 +379,11 @@ public void testObjectRedeclaration2() throws Exception { doTest("idea/testData/completion/basic/common/ObjectRedeclaration2.kt"); } + @TestMetadata("onlyDotSurvives.kt") + public void testOnlyDotSurvives() throws Exception { + doTest("idea/testData/completion/basic/common/onlyDotSurvives.kt"); + } + @TestMetadata("OnlyScopedClassesWithoutExplicit.kt") public void testOnlyScopedClassesWithoutExplicit() throws Exception { doTest("idea/testData/completion/basic/common/OnlyScopedClassesWithoutExplicit.kt");