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