Fixed a problem which sometimes caused expressions to be evaluated in the wrong order.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2010-2012 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.k2js.test.semantics;
|
||||
|
||||
import org.jetbrains.k2js.test.SingleFileTranslationTest;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class DangerousTest extends SingleFileTranslationTest {
|
||||
|
||||
public DangerousTest() {
|
||||
super("dangerous/");
|
||||
}
|
||||
|
||||
public void testIfAsFunArgument() throws Exception {
|
||||
checkFooBoxIsTrue("ifAsFunArgument.kt");
|
||||
}
|
||||
|
||||
public void testIfAsPlusArgument() throws Exception {
|
||||
checkFooBoxIsTrue("ifAsPlusArgument.kt");
|
||||
}
|
||||
|
||||
public void testWhenAsMinusArgument() throws Exception {
|
||||
checkFooBoxIsTrue("whenAsMinusArgument.kt");
|
||||
}
|
||||
|
||||
public void testEvaluationOrder() throws Exception {
|
||||
checkFooBoxIsTrue("evaluationOrder.kt");
|
||||
}
|
||||
|
||||
public void testDangerousInsideDangerous() throws Exception {
|
||||
checkFooBoxIsTrue("dangerousInsideDangerous.kt");
|
||||
}
|
||||
|
||||
public void test2dangerousInExpression() throws Exception {
|
||||
checkFooBoxIsTrue("2dangerousInExpression.kt");
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,8 @@ public final class MiscTest extends AbstractExpressionTest {
|
||||
try {
|
||||
checkFooBoxIsTrue("ifAsExpressionWithThrow.kt");
|
||||
fail();
|
||||
} catch (JavaScriptException e) {
|
||||
}
|
||||
catch (JavaScriptException e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -39,6 +40,11 @@ public class AliasingContext {
|
||||
public JsName getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsName getAliasForExpression(@NotNull JetExpression element) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public static AliasingContext getCleanContext() {
|
||||
@@ -49,6 +55,8 @@ public class AliasingContext {
|
||||
private final Map<DeclarationDescriptor, JsName> aliasesForDescriptors = Maps.newHashMap();
|
||||
@NotNull
|
||||
private final Map<DeclarationDescriptor, JsName> aliasesForThis = Maps.newHashMap();
|
||||
@NotNull
|
||||
private final Map<JetExpression, JsName> aliasesForExpressions = Maps.newHashMap();
|
||||
|
||||
@Nullable
|
||||
private final AliasingContext parent;
|
||||
@@ -60,18 +68,23 @@ public class AliasingContext {
|
||||
@NotNull
|
||||
public AliasingContext withThisAliased(@NotNull DeclarationDescriptor correspondingDescriptor, @NotNull JsName alias) {
|
||||
AliasingContext newContext = new AliasingContext(this);
|
||||
assert !newContext.aliasesForThis.containsKey(correspondingDescriptor);
|
||||
newContext.aliasesForThis.put(correspondingDescriptor, alias);
|
||||
return newContext;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public AliasingContext withAliasesForExpressions(@NotNull Map<JetExpression, JsName> aliasesForExpressions) {
|
||||
AliasingContext newContext = new AliasingContext(this);
|
||||
newContext.aliasesForExpressions.putAll(aliasesForExpressions);
|
||||
return newContext;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AliasingContext getParent() {
|
||||
assert parent != null;
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public JsName getAliasForThis(@NotNull DeclarationDescriptor descriptor) {
|
||||
JsName alias = aliasesForThis.get(descriptor.getOriginal());
|
||||
@@ -89,4 +102,13 @@ public class AliasingContext {
|
||||
}
|
||||
return getParent().getAliasForDescriptor(descriptor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JsName getAliasForExpression(@NotNull JetExpression element) {
|
||||
JsName alias = aliasesForExpressions.get(element);
|
||||
if (alias != null) {
|
||||
return alias;
|
||||
}
|
||||
return getParent().getAliasForExpression(element);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.addVarDeclaration;
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.newVar;
|
||||
|
||||
public class DynamicContext {
|
||||
//TODO: consider renaming to scoping context
|
||||
public final class DynamicContext {
|
||||
|
||||
@NotNull
|
||||
public static DynamicContext rootContext(@NotNull NamingScope rootScope, @NotNull JsBlock globalBlock) {
|
||||
|
||||
@@ -22,9 +22,12 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.Intrinsics;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForElement;
|
||||
|
||||
/**
|
||||
@@ -85,6 +88,11 @@ public final class TranslationContext {
|
||||
return new TranslationContext(staticContext, dynamicContext, aliasingContext.withThisAliased(correspondingDescriptor, alias));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TranslationContext innerContextWithAliasesForExpressions(@NotNull Map<JetExpression, JsName> aliases) {
|
||||
return new TranslationContext(staticContext, dynamicContext, aliasingContext.withAliasesForExpressions(aliases));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsBlock getBlockForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof CallableDescriptor) {
|
||||
|
||||
@@ -34,12 +34,15 @@ import org.jetbrains.k2js.translate.expression.PatternTranslator;
|
||||
import org.jetbrains.k2js.translate.expression.WhenTranslator;
|
||||
import org.jetbrains.k2js.translate.initializer.ClassInitializerTranslator;
|
||||
import org.jetbrains.k2js.translate.initializer.NamespaceInitializerTranslator;
|
||||
import org.jetbrains.k2js.translate.utils.dangerous.DangerousData;
|
||||
import org.jetbrains.k2js.translate.utils.dangerous.DangerousTranslator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.convertToExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.convertToStatement;
|
||||
import static org.jetbrains.k2js.translate.utils.dangerous.DangerousData.collect;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
@@ -77,6 +80,20 @@ public final class Translation {
|
||||
|
||||
@NotNull
|
||||
public static JsNode translateExpression(@NotNull JetExpression expression, @NotNull TranslationContext context) {
|
||||
JsName aliasForExpression = context.aliasingContext().getAliasForExpression(expression);
|
||||
if (aliasForExpression != null) {
|
||||
return aliasForExpression.makeRef();
|
||||
}
|
||||
DangerousData data = collect(expression, context);
|
||||
if (data.shouldBeTranslated()) {
|
||||
return DangerousTranslator.translate(data, context);
|
||||
}
|
||||
return doTranslateExpression(expression, context);
|
||||
}
|
||||
|
||||
//NOTE: use with care
|
||||
@NotNull
|
||||
public static JsNode doTranslateExpression(JetExpression expression, TranslationContext context) {
|
||||
return expression.accept(new ExpressionVisitor(), context);
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +139,6 @@ public final class BindingUtils {
|
||||
Boolean isStatement = context.get(BindingContext.STATEMENT, expression);
|
||||
assert isStatement != null : "Invalid behaviour of get(BindingContext.STATEMENT)";
|
||||
return isStatement;
|
||||
// return IsStatement.isStatement(expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2010-2012 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.k2js.translate.utils.dangerous;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.JetBlockExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* This module uses a methaphor for naming.
|
||||
* <p/>
|
||||
* Dangerous are the nodes that can be expressions in Kotlin but can't be expressions in JavaScript.
|
||||
* These are: when, if, inlined functions.
|
||||
* The issue with them is that we have to translate them to a list of statements. And also all the expressions which must be computed before
|
||||
* the dangerous expressions.
|
||||
* RootNode is a node which contains such an expression. For example, it may be a statement expression belongs to.
|
||||
*/
|
||||
public class DangerousData {
|
||||
|
||||
@NotNull
|
||||
public static DangerousData collect(@NotNull JetExpression expression, @NotNull TranslationContext context) {
|
||||
if (cantContainDangerousElements(expression, context)) {
|
||||
return emptyData();
|
||||
}
|
||||
return doCollectData(expression, context);
|
||||
}
|
||||
|
||||
private static boolean cantContainDangerousElements(@NotNull JetElement element, @NotNull TranslationContext context) {
|
||||
if (element instanceof JetBlockExpression) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static DangerousData doCollectData(@NotNull JetExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
DangerousData data = new DangerousData();
|
||||
FindDangerousVisitor visitor = new FindDangerousVisitor(context.bindingContext());
|
||||
expression.accept(visitor, data);
|
||||
if (!data.exists()) {
|
||||
return emptyData();
|
||||
}
|
||||
data.setRootNode(expression);
|
||||
FindPreviousVisitor findPreviousVisitor = new FindPreviousVisitor();
|
||||
expression.accept(findPreviousVisitor, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
private static final DangerousData EMPTY = new DangerousData() {
|
||||
@Override
|
||||
public boolean exists() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldBeTranslated() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
public static DangerousData emptyData() {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JetExpression> nodesToBeGeneratedBefore = Lists.newArrayList();
|
||||
|
||||
@Nullable
|
||||
private JetExpression dangerousNode = null;
|
||||
|
||||
@Nullable
|
||||
private JetExpression rootNode = null;
|
||||
|
||||
public void setDangerousNode(@NotNull JetExpression dangerousNode) {
|
||||
assert this.dangerousNode == null : "Should be assigned only once";
|
||||
this.dangerousNode = dangerousNode;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<JetExpression> getNodesToBeGeneratedBefore() {
|
||||
return nodesToBeGeneratedBefore;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
public void setNodesToBeGeneratedBefore(@NotNull List<JetExpression> nodesToBeGeneratedBefore) {
|
||||
this.nodesToBeGeneratedBefore = nodesToBeGeneratedBefore;
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
return dangerousNode != null;
|
||||
}
|
||||
|
||||
public boolean shouldBeTranslated() {
|
||||
return exists() && !nodesToBeGeneratedBefore.isEmpty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetExpression getDangerousNode() {
|
||||
assert dangerousNode != null;
|
||||
return dangerousNode;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetExpression getRootNode() {
|
||||
assert rootNode != null;
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
public void setRootNode(@NotNull JetExpression rootNode) {
|
||||
this.rootNode = rootNode;
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2010-2012 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.k2js.translate.utils.dangerous;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class DangerousTranslator extends AbstractTranslator {
|
||||
|
||||
|
||||
@NotNull
|
||||
public static JsNode translate(@NotNull DangerousData data, @NotNull TranslationContext context) {
|
||||
assert data.exists();
|
||||
DangerousTranslator translator = new DangerousTranslator(data, context);
|
||||
return translator.translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final DangerousData data;
|
||||
|
||||
private DangerousTranslator(@NotNull DangerousData data, @NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsNode translate() {
|
||||
Map<JetExpression, JsName> aliasesForExpressions =
|
||||
translateAllExpressionsAndCreateAliasesForThem(data.getNodesToBeGeneratedBefore());
|
||||
TranslationContext contextWithAliases = context().innerContextWithAliasesForExpressions(aliasesForExpressions);
|
||||
return Translation.doTranslateExpression(data.getRootNode(), contextWithAliases);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<JetExpression, JsName> translateAllExpressionsAndCreateAliasesForThem(@NotNull List<JetExpression> expressions) {
|
||||
Map<JetExpression, JsName> aliasesForExpressions = Maps.newHashMap();
|
||||
for (JetExpression expression : expressions) {
|
||||
JsExpression translatedExpression = Translation.translateAsExpression(expression, context());
|
||||
TemporaryVariable aliasForExpression = context().declareTemporary(translatedExpression);
|
||||
context().addStatementToCurrentBlock(aliasForExpression.assignmentExpression().makeStmt());
|
||||
aliasesForExpressions.put(expression, aliasForExpression.name());
|
||||
}
|
||||
return aliasesForExpressions;
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2010-2012 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.k2js.translate.utils.dangerous;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.isStatement;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class FindDangerousVisitor extends JetTreeVisitor<DangerousData> {
|
||||
|
||||
@NotNull
|
||||
private final BindingContext bindingContext;
|
||||
|
||||
public FindDangerousVisitor(@NotNull BindingContext context) {
|
||||
bindingContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitDeclaration(JetDeclaration dcl, DangerousData data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitJetElement(JetElement element, DangerousData data) {
|
||||
if (data.exists()) {
|
||||
return null;
|
||||
}
|
||||
return super.visitJetElement(element, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitWhenExpression(JetWhenExpression expression, DangerousData data) {
|
||||
if (expressionFound(expression, data)) {
|
||||
return null;
|
||||
}
|
||||
return super.visitWhenExpression(expression, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitIfExpression(JetIfExpression expression, DangerousData data) {
|
||||
if (expressionFound(expression, data)) {
|
||||
return null;
|
||||
}
|
||||
return super.visitIfExpression(expression, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitBlockExpression(JetBlockExpression expression, DangerousData data) {
|
||||
if (isStatement(bindingContext, expression)) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return super.visitBlockExpression(expression, data);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean expressionFound(@NotNull JetExpression expression, @NotNull DangerousData data) {
|
||||
if (data.exists()) {
|
||||
return true;
|
||||
}
|
||||
if (!isStatement(bindingContext, expression)) {
|
||||
data.setDangerousNode(expression);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2010-2012 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.k2js.translate.utils.dangerous;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class FindPreviousVisitor extends JetTreeVisitor<DangerousData> {
|
||||
|
||||
@Override
|
||||
public Void visitJetElement(JetElement element, DangerousData data) {
|
||||
if (data.getDangerousNode() == element) {
|
||||
return null;
|
||||
}
|
||||
if (!hasDangerous(element, data)) {
|
||||
addElement(element, data);
|
||||
}
|
||||
else {
|
||||
acceptChildrenThatAreBeforeTheDangerousNode(element, data);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean addElement(@NotNull JetElement element, @NotNull DangerousData data) {
|
||||
if (element instanceof JetExpression) {
|
||||
data.getNodesToBeGeneratedBefore().add((JetExpression)element);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void acceptChildrenThatAreBeforeTheDangerousNode(@NotNull JetElement element, @NotNull DangerousData data) {
|
||||
PsiElement current = element.getFirstChild();
|
||||
while (current != null) {
|
||||
if (current instanceof JetElement) {
|
||||
((JetElement)current).accept(this, data);
|
||||
if (hasDangerous(element, data)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
current = current.getNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitCallExpression(@NotNull JetCallExpression expression, @NotNull DangerousData data) {
|
||||
if (data.getDangerousNode() == expression) {
|
||||
return null;
|
||||
}
|
||||
if (!hasDangerous(expression, data)) {
|
||||
data.getNodesToBeGeneratedBefore().add(expression);
|
||||
}
|
||||
else {
|
||||
acceptArgumentsThatAreBeforeDangerousNode(expression, data);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void acceptArgumentsThatAreBeforeDangerousNode(@NotNull JetCallExpression expression, @NotNull DangerousData data) {
|
||||
for (ValueArgument argument : expression.getValueArguments()) {
|
||||
JetExpression argumentExpression = argument.getArgumentExpression();
|
||||
assert argumentExpression != null;
|
||||
argumentExpression.accept(this, data);
|
||||
if (hasDangerous(argumentExpression, data)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasDangerous(@NotNull JetElement element, @NotNull DangerousData data) {
|
||||
HasDangerousVisitor visitor = new HasDangerousVisitor();
|
||||
element.accept(visitor, data);
|
||||
return visitor.hasDangerous;
|
||||
}
|
||||
|
||||
private static final class HasDangerousVisitor extends JetTreeVisitor<DangerousData> {
|
||||
|
||||
private boolean hasDangerous = false;
|
||||
|
||||
@Override
|
||||
public Void visitJetElement(JetElement element, DangerousData data) {
|
||||
if (element == data.getDangerousNode()) {
|
||||
hasDangerous = true;
|
||||
return null;
|
||||
}
|
||||
element.acceptChildren(this, data);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package foo
|
||||
|
||||
fun box() : Boolean {
|
||||
if (f(0) != -3) {
|
||||
return false
|
||||
}
|
||||
if (f(102) != 201) {
|
||||
return false;
|
||||
}
|
||||
if (f(103) != 100) {
|
||||
return false
|
||||
}
|
||||
if (f(-100) != -100) {
|
||||
return false
|
||||
}
|
||||
if (f(-99) != -201) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun f(i : Int) : Int {
|
||||
var j = i
|
||||
return --j + (if (j < -100) return -100 else --j) + (if (j > 100) return 100 else 0)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package foo
|
||||
|
||||
fun box() : Boolean {
|
||||
if (f(0) != 201) {
|
||||
return false
|
||||
}
|
||||
if (f(1) != 104) {
|
||||
return false
|
||||
}
|
||||
if (f(-2) != -100) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun f(i : Int) : Int {
|
||||
var j = i
|
||||
return ++j + if (j != 1) {(if (j > 0) 100 else return -100) + 2} else 200
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package foo
|
||||
|
||||
var d = 0
|
||||
|
||||
fun f() : Int {
|
||||
d = if (d < 0) -100 else 100
|
||||
return d
|
||||
}
|
||||
|
||||
fun box() : Boolean {
|
||||
d = d-- + f() + when(d) {
|
||||
-100 -> return true
|
||||
1 -> 1
|
||||
else -> return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package foo
|
||||
|
||||
fun box() : Boolean {
|
||||
var i = 0
|
||||
val c = sum(++i, if (i == 0) return false else i + 2)
|
||||
if (c != 4) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun sum(a1 : Int, a2 : Int) = a1 + a2
|
||||
@@ -0,0 +1,10 @@
|
||||
package foo
|
||||
|
||||
fun box() : Boolean {
|
||||
var i = 0
|
||||
var t = ++i + if (i == 0) 0 else 2
|
||||
if (t != 3) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package foo
|
||||
|
||||
fun box() : Boolean {
|
||||
var i = 0
|
||||
var t = ++i + when(i) {
|
||||
3 -> 4
|
||||
1 -> 2
|
||||
0 -> 1
|
||||
else -> 100
|
||||
}
|
||||
if (t != 3) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user