NI: introduce new data flow analysis for try/catch (#KT-28370)
This commit is contained in:
+106
-2
@@ -555,6 +555,30 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
|
||||
DataFlowInfo dataFlowInfoBeforeTry = tryInputContext.dataFlowInfo;
|
||||
|
||||
/* tryOutputContext is tryInputContext rom which all dataFlowInfo about vars
|
||||
* assigned inside try block has been cut. E.g.:
|
||||
* var s: String? = ...
|
||||
* var x: String? = null
|
||||
* x = "" // here we have DFI that x != null and it is tryInputContext
|
||||
* try {
|
||||
* x = null // here was assignment so we cut info about x from context
|
||||
* // or
|
||||
* x = "42"
|
||||
* requireNotNull(s)
|
||||
* } // here we have tryOutputContext with no info about x
|
||||
* // Notice, that in tryOutputContext we also have no info about s
|
||||
* // tryOutputContext is just cut tryInputContext
|
||||
* catch (...) { }
|
||||
* ...
|
||||
*
|
||||
*/
|
||||
|
||||
PreliminaryLoopVisitor tryVisitor = PreliminaryLoopVisitor.visitTryBlock(tryExpression);
|
||||
ExpressionTypingContext tryOutputContext = tryInputContext.replaceDataFlowInfo(
|
||||
tryVisitor.clearDataFlowInfoForAssignedLocalVariables(dataFlowInfoBeforeTry, components.languageVersionSettings)
|
||||
);
|
||||
DataFlowInfo dataFlowInfoAfterTry = tryOutputContext.dataFlowInfo;
|
||||
|
||||
List<KtExpression> catchBlocks = Lists.newArrayList();
|
||||
List<kotlin.Pair<KtExpression, VariableDescriptor>> catchClausesBlocksAndParameters = Lists.newArrayList();
|
||||
|
||||
@@ -580,14 +604,23 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
|
||||
Call callForTry = createCallForSpecialConstruction(tryExpression, tryExpression, arguments);
|
||||
|
||||
MutableDataFlowInfoForArguments dataFlowInfoForArguments = createDataFlowInfoForArgumentsOfTryCall(callForTry, dataFlowInfoBeforeTry, dataFlowInfoBeforeTry);
|
||||
MutableDataFlowInfoForArguments dataFlowInfoForArguments;
|
||||
if (components.languageVersionSettings.supportsFeature(LanguageFeature.NewDataFlowForTryExpressions)) {
|
||||
dataFlowInfoForArguments = createDataFlowInfoForArgumentsOfTryCall(callForTry, dataFlowInfoBeforeTry, dataFlowInfoAfterTry);
|
||||
} else {
|
||||
dataFlowInfoForArguments = createDataFlowInfoForArgumentsOfTryCall(callForTry, dataFlowInfoBeforeTry, dataFlowInfoBeforeTry);
|
||||
}
|
||||
ResolvedCall<FunctionDescriptor> resolvedCall = components.controlStructureTypingUtils
|
||||
.resolveTryAsCall(callForTry, tryExpression, catchClausesBlocksAndParameters, tryInputContext, dataFlowInfoForArguments);
|
||||
KotlinType resultType = resolvedCall.getResultingDescriptor().getReturnType();
|
||||
|
||||
BindingContext bindingContext = tryInputContext.trace.getBindingContext();
|
||||
|
||||
return processTryBranches(tryExpression, tryBlock, tryInputContext, catchBlocks, finallyBlock, bindingContext, resultType);
|
||||
if (components.languageVersionSettings.supportsFeature(LanguageFeature.NewDataFlowForTryExpressions)) {
|
||||
return processTryBranchesWithNewDataFlowAlgorithm(tryExpression, tryBlock, tryOutputContext, dataFlowInfoAfterTry, catchBlocks, finallyBlock, bindingContext, resultType);
|
||||
} else {
|
||||
return processTryBranches(tryExpression, tryBlock, tryInputContext, catchBlocks, finallyBlock, bindingContext, resultType);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -611,6 +644,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
boolean nothingInAllCatchBranches = isCatchBranchesReturnsNothing(catchBlocks, bindingContext);
|
||||
|
||||
// it is not actually correct way (#KT-28370) of computing context, but it's how was in OI
|
||||
// Fix of it is breaking change and allowed with NewDataFlowForTryExpressions language feature.
|
||||
// See [processTryBranchesWithNewDataFlowAlgorithm] function
|
||||
ExpressionTypingContext tryOutputContext = getCleanedContextFromTryWithAssignmentsToVar(tryExpression, nothingInAllCatchBranches, context);
|
||||
|
||||
KotlinTypeInfo result = TypeInfoFactoryKt.createTypeInfo(resultType, tryOutputContext);
|
||||
@@ -627,6 +662,75 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private KotlinTypeInfo processTryBranchesWithNewDataFlowAlgorithm(
|
||||
@NotNull KtTryExpression tryExpression,
|
||||
KtBlockExpression tryBlock,
|
||||
ExpressionTypingContext tryOutputContext,
|
||||
DataFlowInfo dataFlowInfoAfterTry,
|
||||
List<KtExpression> catchBlocks,
|
||||
KtBlockExpression finallyBlock,
|
||||
BindingContext bindingContext,
|
||||
KotlinType resultType
|
||||
) {
|
||||
/*
|
||||
* See [resolveTryExpressionWithNewInference] for the definition of tryOutputContext
|
||||
* Here was added some others context and another definitions:
|
||||
* - catchOutputContextFromNonNothingBranches is a tryOutputContext without information about variables
|
||||
* assigned in non-Nothing catch branches
|
||||
* - catchOutputContextFromAllBranches is tryOutputContext that was cut with assignments from all catch branches
|
||||
* - tryInfo is resolved KotlinTypeInfo of try branch, so its dataFlowInfo contains all interesting infos from try block
|
||||
* (e.g. info about s != null from example in function [resolveTryExpressionWithNewInference])
|
||||
* - finallyTypeInfo is resolved KotlinTypeInfo of finally branch (it's resolved with assumption that we can came into
|
||||
* finally block from any catch block, even if it returns Nothing)
|
||||
* - resultDataFlowInfo is dataFlowInfo that leaves after try/catch/finally (if catch or finally is presented)
|
||||
*
|
||||
*
|
||||
* All analysis passes under strict assumption, that we can fail with exception in any place of try block, so we can't use any
|
||||
* resolved dataFlowInfo from it. But, there is a one case, when we can use it: if there are no catch branches or all catch
|
||||
* branches returns Nothing, so we can reach code after try only if there was no exceptions in try block, so we can use
|
||||
* dataFlowInfo from it (see nothingInAllCatchBranches variable)
|
||||
*/
|
||||
List<Boolean> branchesReturningNothing = whichCatchBranchesReturnNothing(catchBlocks, bindingContext);
|
||||
PreliminaryLoopVisitor catchVisitorForNonNothingBranches = PreliminaryLoopVisitor.visitCatchBlocks(tryExpression, mapNot(branchesReturningNothing));
|
||||
ExpressionTypingContext catchOutputContextFromNonNothingBranches = tryOutputContext.replaceDataFlowInfo(
|
||||
catchVisitorForNonNothingBranches.clearDataFlowInfoForAssignedLocalVariables(dataFlowInfoAfterTry, components.languageVersionSettings)
|
||||
);
|
||||
|
||||
KotlinTypeInfo tryInfo = BindingContextUtils.getRecordedTypeInfo(tryBlock, bindingContext);
|
||||
boolean nothingInAllCatchBranches = CollectionsKt.all(branchesReturningNothing, it -> it);
|
||||
DataFlowInfo nonExceptionalTryCatchesOutputInfo;
|
||||
if (tryInfo == null) {
|
||||
nonExceptionalTryCatchesOutputInfo = DataFlowInfo.Companion.getEMPTY();
|
||||
} else if (nothingInAllCatchBranches) {
|
||||
nonExceptionalTryCatchesOutputInfo = tryInfo.getDataFlowInfo();
|
||||
} else {
|
||||
nonExceptionalTryCatchesOutputInfo = catchOutputContextFromNonNothingBranches.dataFlowInfo;
|
||||
}
|
||||
|
||||
DataFlowInfo resultDataFlowInfo;
|
||||
if (finallyBlock != null) {
|
||||
PreliminaryLoopVisitor catchVisitor = PreliminaryLoopVisitor.visitCatchBlocks(tryExpression);
|
||||
ExpressionTypingContext catchOutputContextFromAllBranches = tryOutputContext.replaceDataFlowInfo(
|
||||
catchVisitor.clearDataFlowInfoForAssignedLocalVariables(dataFlowInfoAfterTry, components.languageVersionSettings)
|
||||
);
|
||||
KotlinTypeInfo finallyTypeInfo = facade.getTypeInfo(finallyBlock, catchOutputContextFromAllBranches);
|
||||
DataFlowInfo finallyDataFlowInfo = finallyTypeInfo.getDataFlowInfo();
|
||||
resultDataFlowInfo = finallyDataFlowInfo.and(nonExceptionalTryCatchesOutputInfo);
|
||||
} else {
|
||||
resultDataFlowInfo = nonExceptionalTryCatchesOutputInfo;
|
||||
}
|
||||
|
||||
return TypeInfoFactoryKt.createTypeInfo(
|
||||
components.dataFlowAnalyzer.checkType(resultType, tryExpression, catchOutputContextFromNonNothingBranches),
|
||||
resultDataFlowInfo
|
||||
);
|
||||
}
|
||||
|
||||
private static List<Boolean> mapNot(List<Boolean> list) {
|
||||
return CollectionsKt.map(list, it -> !it);
|
||||
}
|
||||
|
||||
private static boolean isCatchBranchesReturnsNothing(List<KtExpression> catchBlocks, BindingContext bindingContext) {
|
||||
return CollectionsKt.all(whichCatchBranchesReturnNothing(catchBlocks, bindingContext), it -> it);
|
||||
}
|
||||
|
||||
+15
@@ -73,5 +73,20 @@ class PreliminaryLoopVisitor private constructor() : AssignedVariablesSearcher()
|
||||
tryExpression.tryBlock.accept(visitor, null)
|
||||
return visitor
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun visitCatchBlocks(tryExpression: KtTryExpression): PreliminaryLoopVisitor =
|
||||
visitCatchBlocks(tryExpression, tryExpression.catchClauses.map { true })
|
||||
|
||||
@JvmStatic
|
||||
fun visitCatchBlocks(tryExpression: KtTryExpression, isBlockShouldBeVisited: List<Boolean>): PreliminaryLoopVisitor {
|
||||
val catchClauses = tryExpression.catchClauses
|
||||
assert(catchClauses.size == isBlockShouldBeVisited.size)
|
||||
val visitor = PreliminaryLoopVisitor()
|
||||
catchClauses.zip(isBlockShouldBeVisited)
|
||||
.filter { (_, shouldBeVisited) -> shouldBeVisited }
|
||||
.forEach { (clause, _) -> clause.catchBody?.accept(visitor, null) }
|
||||
return visitor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// !LANGUAGE: +NewDataFlowForTryExpressions
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_VALUE -VARIABLE_WITH_REDUNDANT_INITIALIZER
|
||||
// Related issue: KT-28370
|
||||
|
||||
class ExcA : Exception()
|
||||
class ExcB : Exception()
|
||||
|
||||
fun test1(s: String?) {
|
||||
var t2: Boolean? = true
|
||||
if (t2 != null) {
|
||||
try {
|
||||
t2 = null
|
||||
}
|
||||
catch (e: Exception) {
|
||||
requireNotNull(s)
|
||||
}
|
||||
t2<!UNSAFE_CALL!>.<!>not()
|
||||
s<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
}
|
||||
|
||||
fun test2(s: String?) {
|
||||
var t2: Boolean? = true
|
||||
if (t2 != null) {
|
||||
try {
|
||||
t2 = null
|
||||
}
|
||||
finally {
|
||||
requireNotNull(s)
|
||||
t2 = true
|
||||
}
|
||||
<!DEBUG_INFO_SMARTCAST!>t2<!>.not()
|
||||
<!DEBUG_INFO_SMARTCAST!>s<!>.length
|
||||
}
|
||||
}
|
||||
|
||||
fun test3() {
|
||||
var s: String? = null
|
||||
s = ""
|
||||
try {
|
||||
|
||||
}
|
||||
catch (e: Exception) {
|
||||
s = null
|
||||
return
|
||||
}
|
||||
<!DEBUG_INFO_SMARTCAST!>s<!>.length
|
||||
}
|
||||
|
||||
fun test4() {
|
||||
var s: String? = null
|
||||
s = ""
|
||||
try {
|
||||
|
||||
}
|
||||
catch (e: ExcA) {
|
||||
s = null
|
||||
return
|
||||
}
|
||||
catch (e: ExcB) {
|
||||
|
||||
}
|
||||
<!DEBUG_INFO_SMARTCAST!>s<!>.length
|
||||
}
|
||||
|
||||
fun test5(s: String?) {
|
||||
try {
|
||||
requireNotNull(s)
|
||||
}
|
||||
catch (e: ExcA) {
|
||||
return
|
||||
}
|
||||
catch (e: ExcB) {
|
||||
|
||||
}
|
||||
s<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
fun test6(s: String?) {
|
||||
try {
|
||||
requireNotNull(s)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
return
|
||||
}
|
||||
<!DEBUG_INFO_SMARTCAST!>s<!>.length
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package
|
||||
|
||||
public fun test1(/*0*/ s: kotlin.String?): kotlin.Unit
|
||||
public fun test2(/*0*/ s: kotlin.String?): kotlin.Unit
|
||||
public fun test3(): kotlin.Unit
|
||||
public fun test4(): kotlin.Unit
|
||||
public fun test5(/*0*/ s: kotlin.String?): kotlin.Unit
|
||||
public fun test6(/*0*/ s: kotlin.String?): kotlin.Unit
|
||||
|
||||
public final class ExcA : kotlin.Exception /* = java.lang.Exception */ {
|
||||
public constructor ExcA()
|
||||
public open override /*1*/ /*fake_override*/ val cause: kotlin.Throwable?
|
||||
public open override /*1*/ /*fake_override*/ val message: kotlin.String?
|
||||
public final override /*1*/ /*fake_override*/ fun addSuppressed(/*0*/ exception: kotlin.Throwable!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun fillInStackTrace(): kotlin.Throwable!
|
||||
public open override /*1*/ /*fake_override*/ fun getLocalizedMessage(): kotlin.String!
|
||||
public open override /*1*/ /*fake_override*/ fun getStackTrace(): kotlin.Array<(out) java.lang.StackTraceElement!>!
|
||||
public final override /*1*/ /*fake_override*/ fun getSuppressed(): kotlin.Array<(out) kotlin.Throwable!>!
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun initCause(/*0*/ cause: kotlin.Throwable!): kotlin.Throwable!
|
||||
public open override /*1*/ /*fake_override*/ fun printStackTrace(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintStream!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintWriter!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun setStackTrace(/*0*/ stackTrace: kotlin.Array<(out) java.lang.StackTraceElement!>!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class ExcB : kotlin.Exception /* = java.lang.Exception */ {
|
||||
public constructor ExcB()
|
||||
public open override /*1*/ /*fake_override*/ val cause: kotlin.Throwable?
|
||||
public open override /*1*/ /*fake_override*/ val message: kotlin.String?
|
||||
public final override /*1*/ /*fake_override*/ fun addSuppressed(/*0*/ exception: kotlin.Throwable!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun fillInStackTrace(): kotlin.Throwable!
|
||||
public open override /*1*/ /*fake_override*/ fun getLocalizedMessage(): kotlin.String!
|
||||
public open override /*1*/ /*fake_override*/ fun getStackTrace(): kotlin.Array<(out) java.lang.StackTraceElement!>!
|
||||
public final override /*1*/ /*fake_override*/ fun getSuppressed(): kotlin.Array<(out) kotlin.Throwable!>!
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun initCause(/*0*/ cause: kotlin.Throwable!): kotlin.Throwable!
|
||||
public open override /*1*/ /*fake_override*/ fun printStackTrace(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintStream!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintWriter!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun setStackTrace(/*0*/ stackTrace: kotlin.Array<(out) java.lang.StackTraceElement!>!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// !LANGUAGE: +NewDataFlowForTryExpressions
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_VALUE -VARIABLE_WITH_REDUNDANT_INITIALIZER
|
||||
// Related issue: KT-28370
|
||||
|
||||
fun test1(s1: String?) {
|
||||
var s: String? = null
|
||||
s = ""
|
||||
try {
|
||||
s = ""
|
||||
requireNotNull(s1)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
return
|
||||
}
|
||||
finally {
|
||||
<!OI;DEBUG_INFO_SMARTCAST!>s<!><!NI;UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
<!DEBUG_INFO_SMARTCAST!>s<!>.length
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
public fun test1(/*0*/ s1: kotlin.String?): kotlin.Unit
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// !LANGUAGE: +NewDataFlowForTryExpressions
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_VALUE -VARIABLE_WITH_REDUNDANT_INITIALIZER
|
||||
// Related issue: KT-28370
|
||||
|
||||
class ExcA : Exception()
|
||||
class ExcB : Exception()
|
||||
|
||||
fun test1() {
|
||||
var x: String? = null
|
||||
x = ""
|
||||
|
||||
try {
|
||||
x = null
|
||||
} catch (e: Exception) {
|
||||
<!OI;DEBUG_INFO_SMARTCAST!>x<!><!NI;UNSAFE_CALL!>.<!>length // smartcast shouldn't be allowed (OOME could happen after `x = null`)
|
||||
throw e
|
||||
}
|
||||
finally {
|
||||
// smartcast shouldn't be allowed, `x = null` could've happened
|
||||
<!OI;DEBUG_INFO_SMARTCAST!>x<!><!NI;UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
// smartcast shouldn't be allowed, `x = null` could've happened
|
||||
<!OI;DEBUG_INFO_SMARTCAST!>x<!><!NI;UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
// With old DFA of try/catch info about unsound smartcasts after try
|
||||
// removes only if there is at least one catch branch that not returns Nothing
|
||||
fun test2() {
|
||||
var x: String? = null
|
||||
x = ""
|
||||
|
||||
try {
|
||||
x = null
|
||||
} catch (e: Exception) {
|
||||
// BAD
|
||||
<!OI;DEBUG_INFO_SMARTCAST!>x<!><!NI;UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
finally {
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
fun test3() {
|
||||
var t2: Boolean? = true
|
||||
if (t2 != null) { // or `t2 is Boolean`
|
||||
try {
|
||||
throw Exception()
|
||||
} catch (e: Exception) {
|
||||
t2 = null
|
||||
}
|
||||
<!OI;DEBUG_INFO_SMARTCAST!>t2<!><!NI;UNSAFE_CALL!>.<!>not() // wrong smartcast, NPE
|
||||
}
|
||||
}
|
||||
|
||||
fun test4() {
|
||||
var t2: Boolean? = true
|
||||
if (t2 != null) { // or `t2 is Boolean`
|
||||
try {
|
||||
t2 = null
|
||||
} finally { }
|
||||
<!OI;DEBUG_INFO_SMARTCAST!>t2<!><!NI;UNSAFE_CALL!>.<!>not() // wrong smartcast, NPE
|
||||
}
|
||||
}
|
||||
|
||||
fun test5() {
|
||||
var s1: String? = null
|
||||
var s2: String? = null
|
||||
s1 = ""
|
||||
s2 = ""
|
||||
try {
|
||||
TODO()
|
||||
}
|
||||
catch (e: ExcA) {
|
||||
s1 = ""
|
||||
}
|
||||
catch (e: ExcB) {
|
||||
s2 = null
|
||||
return
|
||||
}
|
||||
finally {
|
||||
<!OI;DEBUG_INFO_SMARTCAST!>s1<!><!NI;UNSAFE_CALL!>.<!>length
|
||||
<!OI;DEBUG_INFO_SMARTCAST!>s2<!><!NI;UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
<!OI;DEBUG_INFO_SMARTCAST!>s1<!><!NI;UNSAFE_CALL!>.<!>length
|
||||
<!DEBUG_INFO_SMARTCAST!>s2<!>.length
|
||||
}
|
||||
|
||||
fun test6(s1: String?, s2: String?) {
|
||||
var s: String? = null
|
||||
s = ""
|
||||
try {
|
||||
s = null
|
||||
requireNotNull(s1)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
return
|
||||
}
|
||||
finally {
|
||||
<!OI;DEBUG_INFO_SMARTCAST!>s<!><!NI;UNSAFE_CALL!>.<!>length
|
||||
requireNotNull(s2)
|
||||
}
|
||||
<!OI;DEBUG_INFO_SMARTCAST!>s<!><!NI;UNSAFE_CALL!>.<!>length
|
||||
<!NI;DEBUG_INFO_SMARTCAST!>s1<!><!OI;UNSAFE_CALL!>.<!>length
|
||||
<!DEBUG_INFO_SMARTCAST!>s2<!>.length
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package
|
||||
|
||||
public fun test1(): kotlin.Unit
|
||||
public fun test2(): kotlin.Unit
|
||||
public fun test3(): kotlin.Unit
|
||||
public fun test4(): kotlin.Unit
|
||||
public fun test5(): kotlin.Unit
|
||||
public fun test6(/*0*/ s1: kotlin.String?, /*1*/ s2: kotlin.String?): kotlin.Unit
|
||||
|
||||
public final class ExcA : kotlin.Exception /* = java.lang.Exception */ {
|
||||
public constructor ExcA()
|
||||
public open override /*1*/ /*fake_override*/ val cause: kotlin.Throwable?
|
||||
public open override /*1*/ /*fake_override*/ val message: kotlin.String?
|
||||
public final override /*1*/ /*fake_override*/ fun addSuppressed(/*0*/ exception: kotlin.Throwable!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun fillInStackTrace(): kotlin.Throwable!
|
||||
public open override /*1*/ /*fake_override*/ fun getLocalizedMessage(): kotlin.String!
|
||||
public open override /*1*/ /*fake_override*/ fun getStackTrace(): kotlin.Array<(out) java.lang.StackTraceElement!>!
|
||||
public final override /*1*/ /*fake_override*/ fun getSuppressed(): kotlin.Array<(out) kotlin.Throwable!>!
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun initCause(/*0*/ cause: kotlin.Throwable!): kotlin.Throwable!
|
||||
public open override /*1*/ /*fake_override*/ fun printStackTrace(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintStream!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintWriter!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun setStackTrace(/*0*/ stackTrace: kotlin.Array<(out) java.lang.StackTraceElement!>!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class ExcB : kotlin.Exception /* = java.lang.Exception */ {
|
||||
public constructor ExcB()
|
||||
public open override /*1*/ /*fake_override*/ val cause: kotlin.Throwable?
|
||||
public open override /*1*/ /*fake_override*/ val message: kotlin.String?
|
||||
public final override /*1*/ /*fake_override*/ fun addSuppressed(/*0*/ exception: kotlin.Throwable!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun fillInStackTrace(): kotlin.Throwable!
|
||||
public open override /*1*/ /*fake_override*/ fun getLocalizedMessage(): kotlin.String!
|
||||
public open override /*1*/ /*fake_override*/ fun getStackTrace(): kotlin.Array<(out) java.lang.StackTraceElement!>!
|
||||
public final override /*1*/ /*fake_override*/ fun getSuppressed(): kotlin.Array<(out) kotlin.Throwable!>!
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun initCause(/*0*/ cause: kotlin.Throwable!): kotlin.Throwable!
|
||||
public open override /*1*/ /*fake_override*/ fun printStackTrace(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintStream!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintWriter!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun setStackTrace(/*0*/ stackTrace: kotlin.Array<(out) java.lang.StackTraceElement!>!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+15
@@ -3266,16 +3266,31 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("correctSmartcasts_after.kt")
|
||||
public void testCorrectSmartcasts_after() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts_after.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("falseNegativeSmartcasts.kt")
|
||||
public void testFalseNegativeSmartcasts() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("falseNegativeSmartcasts_after.kt")
|
||||
public void testFalseNegativeSmartcasts_after() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts_after.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("falsePositiveSmartcasts.kt")
|
||||
public void testFalsePositiveSmartcasts() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("falsePositiveSmartcasts_after.kt")
|
||||
public void testFalsePositiveSmartcasts_after() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts_after.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("tryExpression.kt")
|
||||
public void testTryExpression() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/tryExpression.kt");
|
||||
|
||||
compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
Generated
+15
@@ -3266,16 +3266,31 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("correctSmartcasts_after.kt")
|
||||
public void testCorrectSmartcasts_after() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts_after.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("falseNegativeSmartcasts.kt")
|
||||
public void testFalseNegativeSmartcasts() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("falseNegativeSmartcasts_after.kt")
|
||||
public void testFalseNegativeSmartcasts_after() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts_after.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("falsePositiveSmartcasts.kt")
|
||||
public void testFalsePositiveSmartcasts() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("falsePositiveSmartcasts_after.kt")
|
||||
public void testFalsePositiveSmartcasts_after() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts_after.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("tryExpression.kt")
|
||||
public void testTryExpression() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/tryExpression.kt");
|
||||
|
||||
@@ -119,6 +119,9 @@ enum class LanguageFeature(
|
||||
|
||||
SamConversionForKotlinFunctions(sinceVersion = KOTLIN_1_3, defaultState = State.DISABLED),
|
||||
|
||||
// can be used only with NewInference feature
|
||||
NewDataFlowForTryExpressions(sinceVersion = KOTLIN_1_3, defaultState = State.DISABLED),
|
||||
|
||||
InlineClasses(sinceVersion = KOTLIN_1_3, defaultState = State.ENABLED_WITH_WARNING, kind = UNSTABLE_FEATURE),
|
||||
|
||||
ContractsOnCallsWithImplicitReceiver(sinceVersion = KOTLIN_1_3, defaultState = State.DISABLED),
|
||||
|
||||
Reference in New Issue
Block a user