Test for inline dangerous expressions.

Better FindPreviousVisitor#hasDangerous implementation.
This commit is contained in:
Pavel V. Talanov
2012-03-28 20:51:21 +04:00
parent 31ceb1e7df
commit 87381a06a7
5 changed files with 76 additions and 31 deletions
@@ -50,4 +50,8 @@ public final class DangerousTest extends SingleFileTranslationTest {
public void test2dangerousInExpression() throws Exception { public void test2dangerousInExpression() throws Exception {
checkFooBoxIsTrue("2dangerousInExpression.kt"); checkFooBoxIsTrue("2dangerousInExpression.kt");
} }
public void testDangerousInline() throws Exception {
checkFooBoxIsTrue("dangerousInline.kt");
}
} }
@@ -58,13 +58,13 @@ public class DangerousData {
private static DangerousData doCollectData(@NotNull JetExpression expression, private static DangerousData doCollectData(@NotNull JetExpression expression,
@NotNull TranslationContext context) { @NotNull TranslationContext context) {
DangerousData data = new DangerousData(); DangerousData data = new DangerousData();
FindDangerousVisitor visitor = new FindDangerousVisitor(context.bindingContext()); FindDangerousVisitor visitor = new FindDangerousVisitor(context);
expression.accept(visitor, data); expression.accept(visitor, data);
if (!data.exists()) { if (!data.exists()) {
return emptyData(); return emptyData();
} }
data.setRootNode(expression); data.setRootNode(expression);
FindPreviousVisitor findPreviousVisitor = new FindPreviousVisitor(); FindPreviousVisitor findPreviousVisitor = new FindPreviousVisitor(data);
expression.accept(findPreviousVisitor, data); expression.accept(findPreviousVisitor, data);
return data; return data;
} }
@@ -18,7 +18,8 @@ package org.jetbrains.k2js.translate.utils.dangerous;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.reference.InlinedCallExpressionTranslator;
import static org.jetbrains.k2js.translate.utils.BindingUtils.isStatement; import static org.jetbrains.k2js.translate.utils.BindingUtils.isStatement;
@@ -28,10 +29,10 @@ import static org.jetbrains.k2js.translate.utils.BindingUtils.isStatement;
public final class FindDangerousVisitor extends JetTreeVisitor<DangerousData> { public final class FindDangerousVisitor extends JetTreeVisitor<DangerousData> {
@NotNull @NotNull
private final BindingContext bindingContext; private final TranslationContext context;
public FindDangerousVisitor(@NotNull BindingContext context) { public FindDangerousVisitor(@NotNull TranslationContext context) {
bindingContext = context; this.context = context;
} }
@Override @Override
@@ -65,7 +66,7 @@ public final class FindDangerousVisitor extends JetTreeVisitor<DangerousData> {
@Override @Override
public Void visitBlockExpression(JetBlockExpression expression, DangerousData data) { public Void visitBlockExpression(JetBlockExpression expression, DangerousData data) {
if (isStatement(bindingContext, expression)) { if (isStatement(context.bindingContext(), expression)) {
return null; return null;
} }
else { else {
@@ -73,11 +74,21 @@ public final class FindDangerousVisitor extends JetTreeVisitor<DangerousData> {
} }
} }
@Override
public Void visitCallExpression(JetCallExpression expression, DangerousData data) {
if (InlinedCallExpressionTranslator.shouldBeInlined(expression, context)) {
if (expressionFound(expression, data)) {
return null;
}
}
return super.visitCallExpression(expression, data);
}
private boolean expressionFound(@NotNull JetExpression expression, @NotNull DangerousData data) { private boolean expressionFound(@NotNull JetExpression expression, @NotNull DangerousData data) {
if (data.exists()) { if (data.exists()) {
return true; return true;
} }
if (!isStatement(bindingContext, expression)) { if (!isStatement(context.bindingContext(), expression)) {
data.setDangerousNode(expression); data.setDangerousNode(expression);
return true; return true;
} }
@@ -16,21 +16,39 @@
package org.jetbrains.k2js.translate.utils.dangerous; package org.jetbrains.k2js.translate.utils.dangerous;
import com.google.common.collect.Maps;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import java.util.Map;
/** /**
* @author Pavel Talanov * @author Pavel Talanov
*/ */
//TODO: refactor
public final class FindPreviousVisitor extends JetTreeVisitor<DangerousData> { public final class FindPreviousVisitor extends JetTreeVisitor<DangerousData> {
@NotNull
private final Map<JetElement, Void> hasDangerous = Maps.newHashMap();
public FindPreviousVisitor(@NotNull DangerousData data) {
JetElement node = data.getDangerousNode();
PsiElement last = data.getRootNode().getParent();
while (node != last) {
hasDangerous.put(node, null);
PsiElement parent = node.getParent();
assert parent instanceof JetElement;
node = (JetElement)parent;
}
}
@Override @Override
public Void visitJetElement(JetElement element, DangerousData data) { public Void visitJetElement(JetElement element, DangerousData data) {
if (data.getDangerousNode() == element) { if (data.getDangerousNode() == element) {
return null; return null;
} }
if (!hasDangerous(element, data)) { if (!hasDangerous(element)) {
addElement(element, data); addElement(element, data);
} }
else { else {
@@ -52,7 +70,7 @@ public final class FindPreviousVisitor extends JetTreeVisitor<DangerousData> {
while (current != null) { while (current != null) {
if (current instanceof JetElement) { if (current instanceof JetElement) {
((JetElement)current).accept(this, data); ((JetElement)current).accept(this, data);
if (hasDangerous(element, data)) { if (hasDangerous(element)) {
break; break;
} }
} }
@@ -60,12 +78,32 @@ public final class FindPreviousVisitor extends JetTreeVisitor<DangerousData> {
} }
} }
@Override
public Void visitPrefixExpression(@NotNull JetPrefixExpression expression, @NotNull DangerousData data) {
if (data.getDangerousNode() == expression) {
return null;
}
if (!hasDangerous(expression)) {
addElement(expression, data);
return null;
}
else {
if (hasDangerous(expression.getBaseExpression())) {
return null;
}
else {
//TODO:
throw new IllegalStateException();
}
}
}
@Override @Override
public Void visitCallExpression(@NotNull JetCallExpression expression, @NotNull DangerousData data) { public Void visitCallExpression(@NotNull JetCallExpression expression, @NotNull DangerousData data) {
if (data.getDangerousNode() == expression) { if (data.getDangerousNode() == expression) {
return null; return null;
} }
if (!hasDangerous(expression, data)) { if (!hasDangerous(expression)) {
data.getNodesToBeGeneratedBefore().add(expression); data.getNodesToBeGeneratedBefore().add(expression);
} }
else { else {
@@ -79,30 +117,13 @@ public final class FindPreviousVisitor extends JetTreeVisitor<DangerousData> {
JetExpression argumentExpression = argument.getArgumentExpression(); JetExpression argumentExpression = argument.getArgumentExpression();
assert argumentExpression != null; assert argumentExpression != null;
argumentExpression.accept(this, data); argumentExpression.accept(this, data);
if (hasDangerous(argumentExpression, data)) { if (hasDangerous(argumentExpression)) {
break; break;
} }
} }
} }
private static boolean hasDangerous(@NotNull JetElement element, @NotNull DangerousData data) { private boolean hasDangerous(@NotNull JetElement element) {
HasDangerousVisitor visitor = new HasDangerousVisitor(); return hasDangerous.containsKey(element);
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,9 @@
package foo
var i = 0
inline fun f() = i * 2
fun box() : Boolean {
return (++i + f()) == 3
}