Control-Flow Analysis: Compute STATEMENT slice using control-flow information
This commit is contained in:
@@ -1252,8 +1252,6 @@ public class JetControlFlowProcessor {
|
||||
generateInstructions(subjectExpression);
|
||||
}
|
||||
|
||||
boolean hasElse = false;
|
||||
|
||||
List<JetExpression> branches = new ArrayList<JetExpression>();
|
||||
|
||||
Label doneLabel = builder.createUnboundLabel();
|
||||
@@ -1265,7 +1263,6 @@ public class JetControlFlowProcessor {
|
||||
|
||||
boolean isElse = whenEntry.isElse();
|
||||
if (isElse) {
|
||||
hasElse = true;
|
||||
if (iterator.hasNext()) {
|
||||
trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry));
|
||||
}
|
||||
@@ -1300,9 +1297,6 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
}
|
||||
builder.bindLabel(doneLabel);
|
||||
if (!hasElse && WhenChecker.mustHaveElse(expression, trace)) {
|
||||
trace.report(NO_ELSE_IN_WHEN.on(expression));
|
||||
}
|
||||
|
||||
mergeValues(branches, expression);
|
||||
}
|
||||
@@ -1407,6 +1401,11 @@ public class JetControlFlowProcessor {
|
||||
builder.magic(specifier, specifier, arguments, PseudocodePackage.expectedTypeFor(expectedTypePredicate, arguments), MagicKind.VALUE_CONSUMER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDelegationSpecifierList(@NotNull JetDelegationSpecifierList list) {
|
||||
list.acceptChildren(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetFile(@NotNull JetFile file) {
|
||||
for (JetDeclaration declaration : file.getDeclarations()) {
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableInitState;
|
||||
import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseState;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.PseudoValue;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeUtil;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.Instruction;
|
||||
@@ -121,6 +122,10 @@ public class JetFlowInformationProvider {
|
||||
markUnusedVariables();
|
||||
|
||||
markUnusedLiteralsInBlock();
|
||||
|
||||
markStatements();
|
||||
|
||||
markWhenWithoutElse();
|
||||
}
|
||||
|
||||
public void checkFunction(@Nullable JetType expectedReturnType) {
|
||||
@@ -697,6 +702,48 @@ public class JetFlowInformationProvider {
|
||||
);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Statements
|
||||
|
||||
public void markStatements() {
|
||||
PseudocodeTraverserPackage.traverse(
|
||||
pseudocode, FORWARD, new JetFlowInformationProvider.FunctionVoid1<Instruction>() {
|
||||
@Override
|
||||
public void execute(@NotNull Instruction instruction) {
|
||||
PseudoValue value = instruction instanceof InstructionWithValue
|
||||
? ((InstructionWithValue) instruction).getOutputValue()
|
||||
: null;
|
||||
Pseudocode pseudocode = instruction.getOwner();
|
||||
boolean isUsedAsExpression = !pseudocode.getUsages(value).isEmpty();
|
||||
for (JetElement element : pseudocode.getValueElements(value)) {
|
||||
trace.record(BindingContext.USED_AS_EXPRESSION, element, isUsedAsExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public void markWhenWithoutElse() {
|
||||
PseudocodeTraverserPackage.traverse(
|
||||
pseudocode, FORWARD, new JetFlowInformationProvider.FunctionVoid1<Instruction>() {
|
||||
@Override
|
||||
public void execute(@NotNull Instruction instruction) {
|
||||
PseudoValue value = instruction instanceof InstructionWithValue
|
||||
? ((InstructionWithValue) instruction).getOutputValue()
|
||||
: null;
|
||||
for (JetElement element : instruction.getOwner().getValueElements(value)) {
|
||||
if (element instanceof JetWhenExpression) {
|
||||
JetWhenExpression whenExpression = (JetWhenExpression) element;
|
||||
if (whenExpression.getElseExpression() == null && WhenChecker.mustHaveElse(whenExpression, trace)) {
|
||||
trace.report(NO_ELSE_IN_WHEN.on(whenExpression));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Tail calls
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
|
||||
@@ -37,7 +38,7 @@ public final class WhenChecker {
|
||||
JetType expectedType = trace.get(BindingContext.EXPECTED_EXPRESSION_TYPE, expression);
|
||||
boolean isUnit = expectedType != null && KotlinBuiltIns.getInstance().isUnit(expectedType);
|
||||
// Some "statements" are actually expressions returned from lambdas, their expected types are non-null
|
||||
boolean isStatement = Boolean.TRUE.equals(trace.get(BindingContext.STATEMENT, expression)) && expectedType == null;
|
||||
boolean isStatement = BindingContextUtilPackage.isUsedAsStatement(expression, trace.getBindingContext()) && expectedType == null;
|
||||
|
||||
return !isUnit && !isStatement && !isWhenExhaustive(expression, trace);
|
||||
}
|
||||
|
||||
@@ -33,9 +33,6 @@ import org.jetbrains.jet.lang.types.TypeUtils
|
||||
import org.jetbrains.jet.lang.types.JetType
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction
|
||||
|
||||
fun JetExpression.isStatement(pseudocode: Pseudocode): Boolean =
|
||||
pseudocode.getUsages(pseudocode.getElementValue(this)).isEmpty()
|
||||
|
||||
fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: ReceiverValue): TypePredicate? {
|
||||
val callableDescriptor = resolvedCall.getResultingDescriptor()
|
||||
if (callableDescriptor == null) return null
|
||||
|
||||
@@ -136,7 +136,7 @@ public interface BindingContext {
|
||||
* Has type of current expression has been already resolved
|
||||
*/
|
||||
WritableSlice<JetExpression, Boolean> PROCESSED = Slices.createSimpleSetSlice();
|
||||
WritableSlice<JetElement, Boolean> STATEMENT = Slices.createRemovableSetSlice();
|
||||
WritableSlice<JetElement, Boolean> USED_AS_EXPRESSION = Slices.createRemovableSetSlice();
|
||||
|
||||
WritableSlice<VariableDescriptor, CaptureKind> CAPTURED_IN_CLOSURE = new BasicWritableSlice<VariableDescriptor, CaptureKind>(DO_NOTHING);
|
||||
|
||||
|
||||
@@ -139,3 +139,6 @@ public fun JetReturnExpression.getTargetFunctionDescriptor(context: BindingConte
|
||||
.dropWhile { it is AnonymousFunctionDescriptor }
|
||||
.firstOrNull()
|
||||
}
|
||||
|
||||
public fun JetExpression.isUsedAsExpression(context: BindingContext): Boolean = context[BindingContext.USED_AS_EXPRESSION, this]!!
|
||||
public fun JetExpression.isUsedAsStatement(context: BindingContext): Boolean = !isUsedAsExpression(context)
|
||||
|
||||
-3
@@ -49,7 +49,6 @@ import javax.inject.Inject;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.STATEMENT;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.*;
|
||||
import static org.jetbrains.jet.lang.types.expressions.CoercionStrategy.COERCION_TO_UNIT;
|
||||
|
||||
@@ -253,7 +252,6 @@ public class ExpressionTypingServices {
|
||||
);
|
||||
JetTypeInfo typeInfo = expressionTypingFacade.getTypeInfo(bodyExpression, context, function.hasBlockBody());
|
||||
|
||||
trace.record(STATEMENT, bodyExpression, false);
|
||||
JetType type = typeInfo.getType();
|
||||
if (type != null) {
|
||||
return type;
|
||||
@@ -283,7 +281,6 @@ public class ExpressionTypingServices {
|
||||
if (!(statement instanceof JetExpression)) {
|
||||
continue;
|
||||
}
|
||||
trace.record(STATEMENT, statement);
|
||||
JetExpression statementExpression = (JetExpression) statement;
|
||||
if (!iterator.hasNext()) {
|
||||
result = getTypeOfLastExpressionInBlock(
|
||||
|
||||
-4
@@ -71,10 +71,6 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
||||
}
|
||||
|
||||
public JetTypeInfo visitWhenExpression(JetWhenExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
|
||||
if (isStatement) {
|
||||
contextWithExpectedType.trace.record(BindingContext.STATEMENT, expression);
|
||||
}
|
||||
|
||||
DataFlowUtils.recordExpectedType(contextWithExpectedType.trace, expression, contextWithExpectedType.expectedType);
|
||||
|
||||
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
|
||||
|
||||
@@ -42,6 +42,7 @@ public class ConvertToForEachLoopIntention : JetSelfTargetingIntention<JetExpres
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
is JetBinaryExpression -> element.getRight()
|
||||
|
||||
+2
-12
@@ -28,7 +28,6 @@ import org.jetbrains.jet.plugin.refactoring.introduce.introduceVariable.KotlinIn
|
||||
import org.jetbrains.jet.lang.psi.JetSafeQualifiedExpression
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.plugin.refactoring.inline.KotlinInlineValHandler
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
|
||||
@@ -43,6 +42,7 @@ import org.jetbrains.jet.lang.psi.JetPostfixExpression
|
||||
import org.jetbrains.jet.lang.psi.JetCallExpression
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||
import org.jetbrains.jet.lang.psi.JetElement
|
||||
import org.jetbrains.jet.lang.resolve.bindingContextUtil.isUsedAsStatement
|
||||
|
||||
val NULL_PTR_EXCEPTION = "NullPointerException"
|
||||
val NULL_PTR_EXCEPTION_FQ = "java.lang.NullPointerException"
|
||||
@@ -72,17 +72,7 @@ fun JetExpression.extractExpressionIfSingle(): JetExpression? {
|
||||
return innerExpression
|
||||
}
|
||||
|
||||
fun JetExpression.isStatement(): Boolean {
|
||||
val context = AnalyzerFacadeWithCache.getContextForElement(this)
|
||||
|
||||
val expectedType = context.get(BindingContext.EXPECTED_EXPRESSION_TYPE, this);
|
||||
val isUnit = expectedType != null && KotlinBuiltIns.getInstance().isUnit(expectedType);
|
||||
|
||||
// Some "statements" are actually expressions returned from lambdas, their expected types are non-null
|
||||
val isStatement = context.get(BindingContext.STATEMENT, this) == true && expectedType == null;
|
||||
|
||||
return isStatement || isUnit
|
||||
}
|
||||
fun JetExpression.isStatement(): Boolean = isUsedAsStatement(AnalyzerFacadeWithCache.getContextForElement(this))
|
||||
|
||||
fun JetBinaryExpression.getNonNullExpression(): JetExpression? = when {
|
||||
this.getLeft()?.isNullExpression() == false ->
|
||||
|
||||
+1
-1
@@ -35,9 +35,9 @@ import com.intellij.codeInsight.template.TemplateBuilderImpl
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import org.apache.commons.lang.StringEscapeUtils.escapeJava
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.convertToIfNullExpression
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.isStatement
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.NULL_PTR_EXCEPTION
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.KOTLIN_NULL_PTR_EXCEPTION
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.isStatement
|
||||
|
||||
public class DoubleBangToIfThenIntention : JetSelfTargetingIntention<JetPostfixExpression>("double.bang.to.if.then", javaClass()) {
|
||||
|
||||
|
||||
+1
-2
@@ -32,9 +32,8 @@ import org.jetbrains.jet.plugin.intentions.branchedTransformations.extractExpres
|
||||
import org.jetbrains.jet.lang.psi.JetThrowExpression
|
||||
import org.jetbrains.jet.plugin.JetBundle
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.isNullExpressionOrEmptyBlock
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.isStatement
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.throwsNullPointerExceptionWithNoArguments
|
||||
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.isStatement
|
||||
|
||||
public class IfThenToDoubleBangIntention : JetSelfTargetingIntention<JetIfExpression>("if.then.to.double.bang", javaClass()) {
|
||||
|
||||
|
||||
+1
-1
@@ -25,8 +25,8 @@ import org.jetbrains.jet.lang.psi.JetBinaryExpression
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.convertToIfNotNullExpression
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.introduceValueForCondition
|
||||
import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.isStatement
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.isStableVariable
|
||||
import org.jetbrains.jet.plugin.intentions.branchedTransformations.isStatement
|
||||
|
||||
public class SafeAccessToIfThenIntention : JetSelfTargetingIntention<JetSafeQualifiedExpression>("safe.access.to.if.then", javaClass()) {
|
||||
override fun isApplicableTo(element: JetSafeQualifiedExpression): Boolean = true
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.analyzer.AnalyzerPackage;
|
||||
import org.jetbrains.jet.di.InjectorForBodyResolve;
|
||||
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
@@ -173,6 +174,8 @@ public class ResolveElementCache {
|
||||
assert false : "Invalid type of the topmost parent";
|
||||
}
|
||||
|
||||
new JetFlowInformationProvider(resolveElement, trace).checkDeclaration();
|
||||
|
||||
return trace.getBindingContext();
|
||||
}
|
||||
|
||||
@@ -315,6 +318,10 @@ public class ResolveElementCache {
|
||||
}
|
||||
|
||||
bodyResolver.resolvePropertyAccessors(bodyResolveContext, jetProperty, descriptor);
|
||||
|
||||
for (JetPropertyAccessor accessor : jetProperty.getAccessors()) {
|
||||
new JetFlowInformationProvider(accessor, trace).checkDeclaration();
|
||||
}
|
||||
}
|
||||
|
||||
private static void functionAdditionalResolve(
|
||||
|
||||
+4
-4
@@ -64,6 +64,7 @@ import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder
|
||||
import org.jetbrains.jet.lang.resolve.bindingContextUtil.getTargetFunctionDescriptor
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import org.jetbrains.jet.lang.resolve.OverridingUtil
|
||||
import org.jetbrains.jet.lang.resolve.bindingContextUtil.isUsedAsStatement
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.isAncestor
|
||||
import org.jetbrains.jet.plugin.intentions.declarations.DeclarationUtils
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils
|
||||
@@ -93,7 +94,6 @@ private fun List<Instruction>.getExitPoints(): List<Instruction> =
|
||||
filter { localInstruction -> localInstruction.nextInstructions.any { it !in this } }
|
||||
|
||||
private fun List<Instruction>.getResultType(
|
||||
pseudocode: Pseudocode,
|
||||
bindingContext: BindingContext,
|
||||
options: ExtractionOptions): JetType {
|
||||
fun instructionToType(instruction: Instruction): JetType? {
|
||||
@@ -106,7 +106,7 @@ private fun List<Instruction>.getResultType(
|
||||
}
|
||||
|
||||
if (expression == null) return null
|
||||
if (options.inferUnitTypeForUnusedValues && expression.isStatement(pseudocode)) return null
|
||||
if (options.inferUnitTypeForUnusedValues && expression.isUsedAsStatement(bindingContext)) return null
|
||||
|
||||
return bindingContext[BindingContext.EXPRESSION_TYPE, expression]
|
||||
}
|
||||
@@ -206,8 +206,8 @@ private fun ExtractionData.analyzeControlFlow(
|
||||
val nonLocallyUsedDeclarations = getLocalDeclarationsWithNonLocalUsages(pseudocode, localInstructions, bindingContext)
|
||||
val (declarationsToCopy, declarationsToReport) = nonLocallyUsedDeclarations.partition { it is JetProperty && it.isLocal() }
|
||||
|
||||
val typeOfDefaultFlow = defaultExits.getResultType(pseudocode, bindingContext, options)
|
||||
val returnValueType = valuedReturnExits.getResultType(pseudocode, bindingContext, options)
|
||||
val typeOfDefaultFlow = defaultExits.getResultType(bindingContext, options)
|
||||
val returnValueType = valuedReturnExits.getResultType(bindingContext, options)
|
||||
|
||||
val defaultReturnType = if (returnValueType.isMeaningful()) returnValueType else typeOfDefaultFlow
|
||||
if (defaultReturnType.isError()) return Pair(DefaultControlFlow(DEFAULT_RETURN_TYPE, declarationsToCopy), ErrorMessage.ERROR_TYPES)
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.constants.NullValue;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
@@ -42,7 +43,6 @@ import org.jetbrains.k2js.translate.reference.AccessTranslationUtils;
|
||||
import org.jetbrains.k2js.translate.reference.CallExpressionTranslator;
|
||||
import org.jetbrains.k2js.translate.reference.QualifiedExpressionTranslator;
|
||||
import org.jetbrains.k2js.translate.reference.ReferenceTranslator;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.k2js.translate.utils.mutator.AssignToExpressionMutator;
|
||||
@@ -185,7 +185,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
JsNode thenNode = thenExpression.accept(this, context);
|
||||
JsNode elseNode = elseExpression == null ? null : elseExpression.accept(this, context);
|
||||
|
||||
boolean isKotlinStatement = BindingUtils.isStatement(context.bindingContext(), expression);
|
||||
boolean isKotlinStatement = BindingContextUtilPackage.isUsedAsStatement(expression, context.bindingContext());
|
||||
boolean canBeJsExpression = thenNode instanceof JsExpression && elseNode instanceof JsExpression;
|
||||
if (!isKotlinStatement && canBeJsExpression) {
|
||||
return new JsConditional(testExpression, convertToExpression(thenNode), convertToExpression(elseNode)).source(expression);
|
||||
|
||||
@@ -21,10 +21,10 @@ import com.intellij.openapi.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.k2js.translate.utils.mutator.AssignToExpressionMutator;
|
||||
import org.jetbrains.k2js.translate.utils.mutator.LastExpressionMutator;
|
||||
@@ -39,7 +39,7 @@ public final class WhenTranslator extends AbstractTranslator {
|
||||
public static JsNode translate(@NotNull JetWhenExpression expression, @NotNull TranslationContext context) {
|
||||
WhenTranslator translator = new WhenTranslator(expression, context);
|
||||
|
||||
if (BindingUtils.isStatement(context.bindingContext(), expression)) {
|
||||
if (BindingContextUtilPackage.isUsedAsStatement(expression, context.bindingContext())) {
|
||||
JsBlock jsBlock = new JsBlock();
|
||||
translator.translateAsStatement(jsBlock.getStatements());
|
||||
return jsBlock;
|
||||
@@ -83,25 +83,25 @@ public final class WhenTranslator extends AbstractTranslator {
|
||||
|
||||
JsIf prevIf = null;
|
||||
for (JetWhenEntry entry : whenExpression.getEntries()) {
|
||||
JsStatement statement = withReturnValueCaptured(translateEntryExpression(entry));
|
||||
if (entry.isElse()) {
|
||||
if (prevIf == null) {
|
||||
statements.add(statement);
|
||||
}
|
||||
else {
|
||||
prevIf.setElseStatement(statement);
|
||||
}
|
||||
break;
|
||||
JsBlock entryBody = new JsBlock();
|
||||
JsStatement statement = withReturnValueCaptured(translateEntryExpression(entry, context().innerBlock(entryBody)));
|
||||
if (!entryBody.isEmpty()) {
|
||||
entryBody.getStatements().add(statement);
|
||||
statement = entryBody;
|
||||
}
|
||||
|
||||
JsIf ifStatement = new JsIf(translateConditions(entry), statement);
|
||||
JsStatement statementToAdd = entry.isElse() ? statement : new JsIf(translateConditions(entry), statement);
|
||||
if (prevIf == null) {
|
||||
statements.add(ifStatement);
|
||||
statements.add(statementToAdd);
|
||||
}
|
||||
else {
|
||||
prevIf.setElseStatement(ifStatement);
|
||||
prevIf.setElseStatement(statementToAdd);
|
||||
}
|
||||
prevIf = ifStatement;
|
||||
|
||||
if (entry.isElse()) break;
|
||||
|
||||
assert statementToAdd instanceof JsIf : "Non-else entry expected: " + entry.getText();
|
||||
prevIf = (JsIf) statementToAdd;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,10 +127,10 @@ public final class WhenTranslator extends AbstractTranslator {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsNode translateEntryExpression(@NotNull JetWhenEntry entry) {
|
||||
private JsNode translateEntryExpression(@NotNull JetWhenEntry entry, @NotNull TranslationContext context) {
|
||||
JetExpression expressionToExecute = entry.getExpression();
|
||||
assert expressionToExecute != null : "WhenEntry should have whenExpression to execute.";
|
||||
return Translation.translateExpression(expressionToExecute, context());
|
||||
return Translation.translateExpression(expressionToExecute, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -95,10 +95,6 @@ public final class BindingUtils {
|
||||
return (JsDescriptorUtils.findAncestorClass(superclassDescriptors) != null);
|
||||
}
|
||||
|
||||
public static boolean isStatement(@NotNull BindingContext context, @NotNull JetExpression expression) {
|
||||
return BindingContextUtils.getNotNull(context, BindingContext.STATEMENT, expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetType getTypeByReference(@NotNull BindingContext context,
|
||||
@NotNull JetTypeReference typeReference) {
|
||||
|
||||
+5
-9
@@ -18,11 +18,10 @@ package org.jetbrains.k2js.translate.utils.dangerous;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.reference.InlinedCallExpressionTranslator;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.isStatement;
|
||||
|
||||
public final class FindDangerousVisitor extends JetTreeVisitor<DangerousData> {
|
||||
|
||||
@NotNull
|
||||
@@ -63,12 +62,9 @@ public final class FindDangerousVisitor extends JetTreeVisitor<DangerousData> {
|
||||
|
||||
@Override
|
||||
public Void visitBlockExpression(@NotNull JetBlockExpression expression, DangerousData data) {
|
||||
if (isStatement(context.bindingContext(), expression)) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return super.visitBlockExpression(expression, data);
|
||||
}
|
||||
return BindingContextUtilPackage.isUsedAsStatement(expression, context.bindingContext())
|
||||
? null
|
||||
: super.visitBlockExpression(expression, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,7 +81,7 @@ public final class FindDangerousVisitor extends JetTreeVisitor<DangerousData> {
|
||||
if (data.exists()) {
|
||||
return true;
|
||||
}
|
||||
if (!isStatement(context.bindingContext(), expression)) {
|
||||
if (!BindingContextUtilPackage.isUsedAsStatement(expression, context.bindingContext())) {
|
||||
data.setDangerousNode(expression);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user