diff --git a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java index a83dc2301b6..382c31f4fe6 100644 --- a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java @@ -143,7 +143,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @Override @NotNull public JsNode visitCallExpression(JetCallExpression expression, TranslationContext context) { - JsExpression callee = getCallee(expression, context); + JsExpression callee = translateCallee(expression, context); List arguments = translateArgumentList(expression.getValueArguments(), context); if (isConstructorInvocation(expression, context)) { JsNew constructorCall = new JsNew(callee); @@ -165,7 +165,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { } @NotNull - private JsExpression getCallee(@NotNull JetCallExpression expression, @NotNull TranslationContext context) { + private JsExpression translateCallee(@NotNull JetCallExpression expression, @NotNull TranslationContext context) { JetExpression jetCallee = expression.getCalleeExpression(); if (jetCallee == null) { throw new AssertionError("Call expression with no callee encountered!"); @@ -291,26 +291,30 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsNode visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, @NotNull TranslationContext context) { + return translateQualifiedExpression(expression, context); + } + + @NotNull + private JsNode translateQualifiedExpression(@NotNull JetQualifiedExpression expression, + @NotNull TranslationContext context) { JsInvocation getterCall = translateAsGetterCall(expression, context); if (getterCall != null) { return getterCall; } - return translateAsQualifiedExpression(expression, context); + return translateAsQualifiedAccess(expression, context); } @Nullable - private JsInvocation translateAsGetterCall(@NotNull JetDotQualifiedExpression expression, + private JsInvocation translateAsGetterCall(@NotNull JetQualifiedExpression expression, @NotNull TranslationContext context) { return Translation.propertyAccessTranslator(context).resolveAsPropertyGet(expression); } @NotNull - private JsNode translateAsQualifiedExpression(@NotNull JetDotQualifiedExpression expression, - @NotNull TranslationContext context) { - JsExpression receiver = AstUtil.convertToExpression(expression.getReceiverExpression().accept(this, context)); - JetExpression jetSelector = expression.getSelectorExpression(); - assert jetSelector != null : "Selector should not be null in dot qualified expression."; - JsExpression selector = AstUtil.convertToExpression(jetSelector.accept(this, context)); + private JsNode translateAsQualifiedAccess(@NotNull JetQualifiedExpression expression, + @NotNull TranslationContext context) { + JsExpression receiver = translateReceiver(expression, context); + JsExpression selector = translateSelector(expression, context); assert (selector instanceof JsNameRef || selector instanceof JsInvocation) : "Selector should be a name reference or a method invocation in dot qualified expression."; if (selector instanceof JsInvocation) { @@ -320,6 +324,20 @@ public final class ExpressionVisitor extends TranslatorVisitor { } } + @NotNull + private JsExpression translateSelector(@NotNull JetQualifiedExpression expression, + @NotNull TranslationContext context) { + JetExpression jetSelector = expression.getSelectorExpression(); + assert jetSelector != null : "Selector should not be null in dot qualified expression."; + return AstUtil.convertToExpression(jetSelector.accept(this, context)); + } + + @NotNull + private JsExpression translateReceiver(@NotNull JetQualifiedExpression expression, + @NotNull TranslationContext context) { + return AstUtil.convertToExpression(expression.getReceiverExpression().accept(this, context)); + } + @NotNull private JsNode translateAsQualifiedNameReference(@NotNull JsExpression receiver, @NotNull JsNameRef selector) { selector.setQualifier(receiver); @@ -347,16 +365,8 @@ public final class ExpressionVisitor extends TranslatorVisitor { public JsNode visitPostfixExpression(@NotNull JetPostfixExpression expression, @NotNull TranslationContext context) { return Translation.operationTranslator(context).translatePostfixOperation(expression); - } -// @Override -// @NotNull -// public JsNode visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression, -// @NotNull TranslationContext context) { -// return Translation.typeOperationTranslator(context).translate(expression); -// } - @Override @NotNull public JsNode visitIsExpression(@NotNull JetIsExpression expression, @@ -364,5 +374,16 @@ public final class ExpressionVisitor extends TranslatorVisitor { return Translation.typeOperationTranslator(context).translateIsExpression(expression); } + @Override + @NotNull + public JsNode visitSafeQualifiedExpression(@NotNull JetSafeQualifiedExpression expression, + @NotNull TranslationContext context) { + JsExpression receiver = translateReceiver(expression, context); + JsBinaryOperation nullCheck = new JsBinaryOperation + (JsBinaryOperator.NEQ, receiver, context.program().getNullLiteral()); + JsStatement thenStatement = AstUtil.convertToStatement(translateQualifiedExpression(expression, context)); + return new JsIf(nullCheck, thenStatement, null); + } + } diff --git a/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java index f77e35fecb6..21ed8515701 100644 --- a/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java @@ -13,6 +13,7 @@ import org.jetbrains.jet.lang.descriptors.PropertyGetterDescriptor; import org.jetbrains.jet.lang.descriptors.PropertySetterDescriptor; import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression; import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetQualifiedExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; @@ -33,7 +34,7 @@ public final class PropertyAccessTranslator extends AbstractTranslator { } @Nullable - public JsInvocation resolveAsPropertyGet(@NotNull JetDotQualifiedExpression expression) { + public JsInvocation resolveAsPropertyGet(@NotNull JetQualifiedExpression expression) { JetExpression selectorExpression = expression.getSelectorExpression(); assert selectorExpression != null : "Selector should not be null."; JsName getterName = getPropertyGetterName(selectorExpression); @@ -54,9 +55,9 @@ public final class PropertyAccessTranslator extends AbstractTranslator { @NotNull private JsInvocation translateReceiverAndReturnAccessorInvocation - (@NotNull JetDotQualifiedExpression dotQualifiedExpression, @NotNull JsName accessorName) { + (@NotNull JetQualifiedExpression qualifiedExpression, @NotNull JsName accessorName) { JsNode node = Translation.expressionTranslator(translationContext()) - .translate(dotQualifiedExpression.getReceiverExpression()); + .translate(qualifiedExpression.getReceiverExpression()); JsNameRef result = accessorName.makeRef(); result.setQualifier(AstUtil.convertToExpression(node)); return AstUtil.newInvocation(result); diff --git a/translator/test/org/jetbrains/k2js/test/PropertyAccessorTest.java b/translator/test/org/jetbrains/k2js/test/PropertyAccessorTest.java index aa410782026..1d604d9411d 100644 --- a/translator/test/org/jetbrains/k2js/test/PropertyAccessorTest.java +++ b/translator/test/org/jetbrains/k2js/test/PropertyAccessorTest.java @@ -39,6 +39,11 @@ public final class PropertyAccessorTest extends AbstractClassTest { testFooBoxIsTrue("customSetter.kt"); } + @Test + public void safeCall() throws Exception { + testFooBoxIsTrue("safeCall.kt"); + } + //TODO test // @Test // public void namespaceCustomAccessors() throws Exception { diff --git a/translator/test/org/jetbrains/k2js/test/RTTITest.java b/translator/test/org/jetbrains/k2js/test/RTTITest.java index b6c52390505..4af82cc409c 100644 --- a/translator/test/org/jetbrains/k2js/test/RTTITest.java +++ b/translator/test/org/jetbrains/k2js/test/RTTITest.java @@ -23,5 +23,4 @@ public class RTTITest extends AbstractClassTest { public void notIsOtherClass() throws Exception { testFooBoxIsTrue("notIsOtherClass.kt"); } - } diff --git a/translator/testFiles/propertyAccess/cases/safeCall.kt b/translator/testFiles/propertyAccess/cases/safeCall.kt new file mode 100644 index 00000000000..2a918b76ff8 --- /dev/null +++ b/translator/testFiles/propertyAccess/cases/safeCall.kt @@ -0,0 +1,13 @@ +namespace foo + +class A() { + fun doSomething() { + + } +} + +fun box() : Boolean { + var a : A? = null; + a?.doSomething() + return true; +} \ No newline at end of file