From 285d5d06c707590e91b3b8d2fae4669ea04bbfc0 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 1 Sep 2015 19:16:27 +0300 Subject: [PATCH] More precise value reassignment analysis. #KT-7418 Fixed. #KT-6902 Fixed. Variable can now be "exactly initialized", "may be initialized" and "not initialized". A set of relevant tests. Some fixed tests. --- .../cfg/JetFlowInformationProvider.java | 17 ++-- .../kotlin/cfg/PseudocodeVariablesData.java | 89 +++++++++++++------ .../basic/IfWithUninitialized.instructions | 16 ++-- ...eferenceToPropertyInitializer.instructions | 6 +- .../varInitializationInIfInCycle.instructions | 6 +- .../lexicalScopes/forScope.instructions | 6 +- .../tests/reassignment/afterfor.kt | 10 +++ .../tests/reassignment/afterfor.txt | 3 + .../diagnostics/tests/reassignment/dowhile.kt | 10 +++ .../tests/reassignment/dowhile.txt | 3 + .../diagnostics/tests/reassignment/else.kt | 11 +++ .../diagnostics/tests/reassignment/else.txt | 3 + .../diagnostics/tests/reassignment/foronly.kt | 9 ++ .../tests/reassignment/foronly.txt | 3 + .../diagnostics/tests/reassignment/if.kt | 10 +++ .../diagnostics/tests/reassignment/if.txt | 3 + .../diagnostics/tests/reassignment/ifelse.kt | 13 +++ .../diagnostics/tests/reassignment/ifelse.txt | 3 + .../tests/reassignment/noifelse.kt | 6 ++ .../tests/reassignment/noifelse.txt | 3 + .../diagnostics/tests/reassignment/when.kt | 10 +++ .../diagnostics/tests/reassignment/when.txt | 3 + .../tests/reassignment/whiletrue.kt | 11 +++ .../tests/reassignment/whiletrue.txt | 3 + .../checkers/JetDiagnosticsTestGenerated.java | 63 +++++++++++++ j2k/testData/fileOrElement/issues/kt-807.kt | 2 +- 26 files changed, 269 insertions(+), 53 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/reassignment/afterfor.kt create mode 100644 compiler/testData/diagnostics/tests/reassignment/afterfor.txt create mode 100644 compiler/testData/diagnostics/tests/reassignment/dowhile.kt create mode 100644 compiler/testData/diagnostics/tests/reassignment/dowhile.txt create mode 100644 compiler/testData/diagnostics/tests/reassignment/else.kt create mode 100644 compiler/testData/diagnostics/tests/reassignment/else.txt create mode 100644 compiler/testData/diagnostics/tests/reassignment/foronly.kt create mode 100644 compiler/testData/diagnostics/tests/reassignment/foronly.txt create mode 100644 compiler/testData/diagnostics/tests/reassignment/if.kt create mode 100644 compiler/testData/diagnostics/tests/reassignment/if.txt create mode 100644 compiler/testData/diagnostics/tests/reassignment/ifelse.kt create mode 100644 compiler/testData/diagnostics/tests/reassignment/ifelse.txt create mode 100644 compiler/testData/diagnostics/tests/reassignment/noifelse.kt create mode 100644 compiler/testData/diagnostics/tests/reassignment/noifelse.txt create mode 100644 compiler/testData/diagnostics/tests/reassignment/when.kt create mode 100644 compiler/testData/diagnostics/tests/reassignment/when.txt create mode 100644 compiler/testData/diagnostics/tests/reassignment/whiletrue.kt create mode 100644 compiler/testData/diagnostics/tests/reassignment/whiletrue.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetFlowInformationProvider.java index 8f4d8edaef5..b2dd1bef52e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetFlowInformationProvider.java @@ -372,14 +372,14 @@ public class JetFlowInformationProvider { if (!(element instanceof JetSimpleNameExpression)) return; - boolean isInitialized = ctxt.exitInitState.isInitialized; + boolean isDefinitelyInitialized = ctxt.exitInitState.definitelyInitialized(); VariableDescriptor variableDescriptor = ctxt.variableDescriptor; if (variableDescriptor instanceof PropertyDescriptor) { if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) { - isInitialized = true; + isDefinitelyInitialized = true; } } - if (!isInitialized && !varWithUninitializedErrorGenerated.contains(variableDescriptor)) { + if (!isDefinitelyInitialized && !varWithUninitializedErrorGenerated.contains(variableDescriptor)) { if (!(variableDescriptor instanceof PropertyDescriptor)) { varWithUninitializedErrorGenerated.add(variableDescriptor); } @@ -412,7 +412,7 @@ public class JetFlowInformationProvider { } } - boolean isInitializedNotHere = ctxt.enterInitState.isInitialized; + boolean mayBeInitializedNotHere = ctxt.enterInitState.mayBeInitialized(); boolean hasBackingField = true; if (variableDescriptor instanceof PropertyDescriptor) { hasBackingField = trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor); @@ -437,7 +437,7 @@ public class JetFlowInformationProvider { } boolean isThisOrNoDispatchReceiver = PseudocodeUtil.isThisOrNoDispatchReceiver(writeValueInstruction, trace.getBindingContext()); - if ((isInitializedNotHere || !hasBackingField || !isThisOrNoDispatchReceiver) && !variableDescriptor.isVar()) { + if ((mayBeInitializedNotHere || !hasBackingField || !isThisOrNoDispatchReceiver) && !variableDescriptor.isVar()) { boolean hasReassignMethodReturningUnit = false; JetSimpleNameExpression operationReference = null; PsiElement parent = expression.getParent(); @@ -483,7 +483,7 @@ public class JetFlowInformationProvider { private boolean checkAssignmentBeforeDeclaration(@NotNull VariableInitContext ctxt, @NotNull JetExpression expression) { if (!ctxt.enterInitState.isDeclared && !ctxt.exitInitState.isDeclared - && !ctxt.enterInitState.isInitialized && ctxt.exitInitState.isInitialized) { + && !ctxt.enterInitState.mayBeInitialized() && ctxt.exitInitState.mayBeInitialized()) { report(Errors.INITIALIZATION_BEFORE_DECLARATION.on(expression, ctxt.variableDescriptor), ctxt); return true; } @@ -492,7 +492,8 @@ public class JetFlowInformationProvider { private boolean checkInitializationUsingBackingField(@NotNull VariableInitContext ctxt, @NotNull JetExpression expression) { VariableDescriptor variableDescriptor = ctxt.variableDescriptor; - if (variableDescriptor instanceof PropertyDescriptor && !ctxt.enterInitState.isInitialized && ctxt.exitInitState.isInitialized) { + if (variableDescriptor instanceof PropertyDescriptor + && !ctxt.enterInitState.mayBeInitialized() && ctxt.exitInitState.mayBeInitialized()) { if (!variableDescriptor.isVar()) return false; if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) return false; PsiElement property = DescriptorToSourceUtils.descriptorToDeclaration(variableDescriptor); @@ -590,7 +591,7 @@ public class JetFlowInformationProvider { for (VariableDescriptor variable : declaredVariables) { if (variable instanceof PropertyDescriptor) { PseudocodeVariablesData.VariableInitState variableInitState = initializers.getIncoming().get(variable); - if (variableInitState != null && variableInitState.isInitialized) continue; + if (variableInitState != null && variableInitState.definitelyInitialized()) continue; trace.record(BindingContext.IS_UNINITIALIZED, (PropertyDescriptor) variable); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/PseudocodeVariablesData.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/PseudocodeVariablesData.java index 3ee40cb1353..9c8a90753f0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/PseudocodeVariablesData.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/PseudocodeVariablesData.java @@ -155,7 +155,7 @@ public class PseudocodeVariablesData { boolean declaredOutsideThisDeclaration = declaredIn == null //declared outside this pseudocode || declaredIn.getLexicalScopeForContainingDeclaration() != instruction.getLexicalScope().getLexicalScopeForContainingDeclaration(); - return VariableInitState.create(/*isInitialized=*/declaredOutsideThisDeclaration); + return VariableInitState.create(/*initState=*/declaredOutsideThisDeclaration); } @NotNull @@ -169,20 +169,21 @@ public class PseudocodeVariablesData { Map enterInstructionData = Maps.newHashMap(); for (VariableDescriptor variable : variablesInScope) { - boolean isInitialized = true; + TriInitState initState = null; boolean isDeclared = true; for (Map edgeData : incomingEdgesData) { - VariableInitState initState = edgeData.get(variable); - if (initState != null) { - if (!initState.isInitialized) { - isInitialized = false; - } - if (!initState.isDeclared) { + VariableInitState varControlFlowState = edgeData.get(variable); + if (varControlFlowState != null) { + initState = initState != null ? initState.merge(varControlFlowState.initState) : varControlFlowState.initState; + if (!varControlFlowState.isDeclared) { isDeclared = false; } } } - enterInstructionData.put(variable, VariableInitState.create(isInitialized, isDeclared)); + if (initState == null) { + throw new AssertionError("An empty set of incoming edges data"); + } + enterInstructionData.put(variable, VariableInitState.create(initState, isDeclared)); } return enterInstructionData; } @@ -217,8 +218,8 @@ public class PseudocodeVariablesData { if (enterInitState == null) { enterInitState = getDefaultValueForInitializers(variable, instruction, lexicalScopeVariableInfo); } - if (enterInitState == null || !enterInitState.isInitialized || !enterInitState.isDeclared) { - boolean isInitialized = enterInitState != null && enterInitState.isInitialized; + if (enterInitState == null || !enterInitState.mayBeInitialized() || !enterInitState.isDeclared) { + boolean isInitialized = enterInitState != null && enterInitState.mayBeInitialized(); VariableInitState variableDeclarationInfo = VariableInitState.create(isInitialized, true); exitInstructionData.put(variable, variableDeclarationInfo); } @@ -279,28 +280,54 @@ public class PseudocodeVariablesData { ); } + private enum TriInitState { + INITIALIZED("I"), UNKNOWN("I?"), NOT_INITIALIZED(""); + + private final String s; + + TriInitState(String s) { + this.s = s; + } + + private TriInitState merge(@NotNull TriInitState other) { + if (this == other) return this; + return UNKNOWN; + } + + @Override + public String toString() { + return s; + } + } + public static class VariableInitState { - public final boolean isInitialized; + + public final TriInitState initState; public final boolean isDeclared; - private VariableInitState(boolean isInitialized, boolean isDeclared) { - this.isInitialized = isInitialized; + private VariableInitState(TriInitState initState, boolean isDeclared) { + this.initState = initState; this.isDeclared = isDeclared; } - private static final VariableInitState VS_TT = new VariableInitState(true, true); - private static final VariableInitState VS_TF = new VariableInitState(true, false); - private static final VariableInitState VS_FT = new VariableInitState(false, true); - private static final VariableInitState VS_FF = new VariableInitState(false, false); + private static final VariableInitState VS_IT = new VariableInitState(TriInitState.INITIALIZED, true); + private static final VariableInitState VS_IF = new VariableInitState(TriInitState.INITIALIZED, false); + private static final VariableInitState VS_UT = new VariableInitState(TriInitState.UNKNOWN, true); + private static final VariableInitState VS_UF = new VariableInitState(TriInitState.UNKNOWN, false); + private static final VariableInitState VS_NT = new VariableInitState(TriInitState.NOT_INITIALIZED, true); + private static final VariableInitState VS_NF = new VariableInitState(TriInitState.NOT_INITIALIZED, false); + private static VariableInitState create(TriInitState initState, boolean isDeclared) { + switch (initState) { + case INITIALIZED: return isDeclared ? VS_IT : VS_IF; + case UNKNOWN: return isDeclared ? VS_UT : VS_UF; + default: return isDeclared ? VS_NT : VS_NF; + } + } + private static VariableInitState create(boolean isInitialized, boolean isDeclared) { - if (isInitialized) { - if (isDeclared) return VS_TT; - return VS_TF; - } - if (isDeclared) return VS_FT; - return VS_FF; + return create(isInitialized ? TriInitState.INITIALIZED : TriInitState.NOT_INITIALIZED, isDeclared); } private static VariableInitState create(boolean isInitialized) { @@ -311,14 +338,22 @@ public class PseudocodeVariablesData { return create(true, isDeclaredHere || (mergedEdgesData != null && mergedEdgesData.isDeclared)); } + public boolean definitelyInitialized() { + return initState == TriInitState.INITIALIZED; + } + + public boolean mayBeInitialized() { + return initState != TriInitState.NOT_INITIALIZED; + } + @Override public String toString() { - if (!isInitialized && !isDeclared) return "-"; - return (isInitialized ? "I" : "") + (isDeclared ? "D" : ""); + if (initState == TriInitState.NOT_INITIALIZED && !isDeclared) return "-"; + return initState + (isDeclared ? "D" : ""); } } - public static enum VariableUseState { + public enum VariableUseState { READ(3), WRITTEN_AFTER_READ(2), ONLY_WRITTEN_NEVER_READ(1), diff --git a/compiler/testData/cfg-variables/basic/IfWithUninitialized.instructions b/compiler/testData/cfg-variables/basic/IfWithUninitialized.instructions index 1acb1c96283..2f1c7309f78 100644 --- a/compiler/testData/cfg-variables/basic/IfWithUninitialized.instructions +++ b/compiler/testData/cfg-variables/basic/IfWithUninitialized.instructions @@ -10,7 +10,7 @@ fun foo() { } --------------------- L0: - 1 INIT: in: {} out: {} USE: in: {} out: {} + 1 INIT: in: {} out: {} USE: in: {} out: {} 2 mark({ val b: Boolean if (1 < 2) { use(b) } else { b = true } }) v(val b: Boolean) INIT: in: {} out: {b=D} mark(if (1 < 2) { use(b) } else { b = true }) INIT: in: {b=D} out: {b=D} @@ -19,23 +19,23 @@ L0: mark(1 < 2) call(1 < 2, compareTo|, ) -> jf(L2|) - 3 mark({ use(b) }) USE: in: {b=READ} out: {b=READ} - r(b) -> USE: in: {} out: {b=READ} + 3 mark({ use(b) }) USE: in: {b=READ} out: {b=READ} + r(b) -> USE: in: {} out: {b=READ} mark(use(b)) call(use(b), use|) -> - 2 jmp(L3) USE: in: {} out: {} + 2 jmp(L3) USE: in: {} out: {} L2 [else branch]: 3 mark({ b = true }) - r(true) -> USE: in: {b=ONLY_WRITTEN_NEVER_READ} out: {b=ONLY_WRITTEN_NEVER_READ} - w(b|) INIT: in: {b=D} out: {b=ID} USE: in: {} out: {b=ONLY_WRITTEN_NEVER_READ} + r(true) -> USE: in: {b=ONLY_WRITTEN_NEVER_READ} out: {b=ONLY_WRITTEN_NEVER_READ} + w(b|) INIT: in: {b=D} out: {b=ID} USE: in: {} out: {b=ONLY_WRITTEN_NEVER_READ} L3 ['if' expression result]: - 2 merge(if (1 < 2) { use(b) } else { b = true }|, !) -> INIT: in: {b=D} out: {b=D} + 2 merge(if (1 < 2) { use(b) } else { b = true }|, !) -> INIT: in: {b=I?D} out: {b=I?D} L1: 1 INIT: in: {} out: {} error: sink: - USE: in: {} out: {} + USE: in: {} out: {} ===================== == use == fun use(vararg a: Any?) = a diff --git a/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.instructions b/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.instructions index c75b8127a86..86ce0a95d9e 100644 --- a/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.instructions +++ b/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.instructions @@ -10,7 +10,7 @@ L0: v(val sum: (Int)->Int = { (x: Int) -> sum(x - 1) + x }) INIT: in: {} out: {sum=D} mark({ (x: Int) -> sum(x - 1) + x }) INIT: in: {sum=D} out: {sum=D} jmp?(L2) - d({ (x: Int) -> sum(x - 1) + x }) USE: in: {sum=READ} out: {sum=READ} + d({ (x: Int) -> sum(x - 1) + x }) USE: in: {sum=READ} out: {sum=READ} L2 [after local declaration]: r({ (x: Int) -> sum(x - 1) + x }) -> w(sum|) INIT: in: {sum=D} out: {sum=ID} @@ -19,7 +19,7 @@ L1: error: INIT: in: {} out: {} sink: - INIT: in: {sum=D} out: {sum=D} USE: in: {} out: {} + INIT: in: {sum=I?D} out: {sum=I?D} USE: in: {} out: {} ===================== == anonymous_0 == { (x: Int) -> @@ -101,7 +101,7 @@ L1: error: INIT: in: {} out: {} sink: - INIT: in: {obj=D} out: {obj=D} USE: in: {} out: {} + INIT: in: {obj=I?D} out: {obj=I?D} USE: in: {} out: {} ===================== == foo == fun foo() { diff --git a/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.instructions b/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.instructions index 078d0b43fde..30e173c5232 100644 --- a/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.instructions +++ b/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.instructions @@ -23,9 +23,9 @@ L0: v(i) INIT: in: {numbers=ID} out: {i=D, numbers=ID} L2 [loop entry point]: L6 [condition entry point]: - jmp?(L3) INIT: in: {i=D, numbers=ID} out: {i=D, numbers=ID} + jmp?(L3) INIT: in: {i=I?D, numbers=ID} out: {i=I?D, numbers=ID} magic[LOOP_RANGE_ITERATION](numbers|) -> - w(i|) INIT: in: {i=D, numbers=ID} out: {i=ID, numbers=ID} + w(i|) INIT: in: {i=I?D, numbers=ID} out: {i=ID, numbers=ID} mark(for (i in numbers) { val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) continue }) INIT: in: {i=ID, numbers=ID} out: {i=ID, numbers=ID} USE: in: {} out: {} L4 [body entry point]: 4 mark({ val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) continue }) @@ -53,7 +53,7 @@ L8 ['if' expression result]: - 3 jmp(L2) L3 [loop exit point]: L5 [body exit point]: - read (Unit) INIT: in: {i=D, numbers=ID} out: {i=D, numbers=ID} + read (Unit) INIT: in: {i=I?D, numbers=ID} out: {i=I?D, numbers=ID} L1: 1 INIT: in: {numbers=ID} out: {numbers=ID} error: diff --git a/compiler/testData/cfg-variables/lexicalScopes/forScope.instructions b/compiler/testData/cfg-variables/lexicalScopes/forScope.instructions index f18bb5957c0..7d8f4e441b8 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/forScope.instructions +++ b/compiler/testData/cfg-variables/lexicalScopes/forScope.instructions @@ -19,9 +19,9 @@ L0: v(i) INIT: in: {} out: {i=D} L2 [loop entry point]: L6 [condition entry point]: - jmp?(L3) INIT: in: {i=D} out: {i=D} + jmp?(L3) INIT: in: {i=I?D} out: {i=I?D} magic[LOOP_RANGE_ITERATION](1..10|) -> - w(i|) INIT: in: {i=D} out: {i=ID} + w(i|) INIT: in: {i=I?D} out: {i=ID} mark(for (i in 1..10) { val a = i }) INIT: in: {i=ID} out: {i=ID} L4 [body entry point]: 4 mark({ val a = i }) @@ -31,7 +31,7 @@ L4 [body entry point]: 3 jmp(L2) INIT: in: {i=ID} out: {i=ID} USE: in: {i=READ} out: {i=READ} L3 [loop exit point]: L5 [body exit point]: - read (Unit) INIT: in: {i=D} out: {i=D} + read (Unit) INIT: in: {i=I?D} out: {i=I?D} 2 mark("after") INIT: in: {} out: {} r("after") -> L1: diff --git a/compiler/testData/diagnostics/tests/reassignment/afterfor.kt b/compiler/testData/diagnostics/tests/reassignment/afterfor.kt new file mode 100644 index 00000000000..a685518d3ef --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/afterfor.kt @@ -0,0 +1,10 @@ +// !DIAGNOSTICS: -UNUSED_VALUE + +fun foo(k: Int): Int { + val i: Int + for (j in 1..k) { + i = j + } + i = 6 + return i +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/reassignment/afterfor.txt b/compiler/testData/diagnostics/tests/reassignment/afterfor.txt new file mode 100644 index 00000000000..c525fdbc422 --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/afterfor.txt @@ -0,0 +1,3 @@ +package + +internal fun foo(/*0*/ k: kotlin.Int): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/reassignment/dowhile.kt b/compiler/testData/diagnostics/tests/reassignment/dowhile.kt new file mode 100644 index 00000000000..c526242a8b1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/dowhile.kt @@ -0,0 +1,10 @@ +// !DIAGNOSTICS: -UNUSED_VALUE + +fun foo(): Int { + val i: Int + var j = 0 + do { + i = ++j + } while (j < 5) + return i +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/reassignment/dowhile.txt b/compiler/testData/diagnostics/tests/reassignment/dowhile.txt new file mode 100644 index 00000000000..de1d6f17577 --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/dowhile.txt @@ -0,0 +1,3 @@ +package + +internal fun foo(): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/reassignment/else.kt b/compiler/testData/diagnostics/tests/reassignment/else.kt new file mode 100644 index 00000000000..f9df6a8afba --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/else.kt @@ -0,0 +1,11 @@ +// !DIAGNOSTICS: -UNUSED_VALUE + +fun foo(f: Boolean): Int { + val i: Int + if (f) {} + else { + i = 2 + } + i = 3 + return i +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/reassignment/else.txt b/compiler/testData/diagnostics/tests/reassignment/else.txt new file mode 100644 index 00000000000..349483c63ec --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/else.txt @@ -0,0 +1,3 @@ +package + +internal fun foo(/*0*/ f: kotlin.Boolean): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/reassignment/foronly.kt b/compiler/testData/diagnostics/tests/reassignment/foronly.kt new file mode 100644 index 00000000000..c7598dd026d --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/foronly.kt @@ -0,0 +1,9 @@ +// !DIAGNOSTICS: -UNUSED_VALUE + +fun foo(k: Int): Int { + val i: Int + for (j in 1..k) { + i = j + } + return i +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/reassignment/foronly.txt b/compiler/testData/diagnostics/tests/reassignment/foronly.txt new file mode 100644 index 00000000000..c525fdbc422 --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/foronly.txt @@ -0,0 +1,3 @@ +package + +internal fun foo(/*0*/ k: kotlin.Int): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/reassignment/if.kt b/compiler/testData/diagnostics/tests/reassignment/if.kt new file mode 100644 index 00000000000..3d3edc4d1b7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/if.kt @@ -0,0 +1,10 @@ +// !DIAGNOSTICS: -UNUSED_VALUE + +fun foo(f: Boolean): Int { + val i: Int + if (f) { + i = 1 + } + i = 3 + return i +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/reassignment/if.txt b/compiler/testData/diagnostics/tests/reassignment/if.txt new file mode 100644 index 00000000000..349483c63ec --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/if.txt @@ -0,0 +1,3 @@ +package + +internal fun foo(/*0*/ f: kotlin.Boolean): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/reassignment/ifelse.kt b/compiler/testData/diagnostics/tests/reassignment/ifelse.kt new file mode 100644 index 00000000000..abde9286ce4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/ifelse.kt @@ -0,0 +1,13 @@ +// !DIAGNOSTICS: -UNUSED_VALUE + +fun foo(f: Boolean): Int { + val i: Int + if (f) { + i = 1 + } + else { + i = 2 + } + i = 3 + return i +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/reassignment/ifelse.txt b/compiler/testData/diagnostics/tests/reassignment/ifelse.txt new file mode 100644 index 00000000000..349483c63ec --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/ifelse.txt @@ -0,0 +1,3 @@ +package + +internal fun foo(/*0*/ f: kotlin.Boolean): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/reassignment/noifelse.kt b/compiler/testData/diagnostics/tests/reassignment/noifelse.kt new file mode 100644 index 00000000000..b096df5bcdb --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/noifelse.kt @@ -0,0 +1,6 @@ +fun foo(f: Boolean): Int { + val i: Int + if (f) {} + i = 3 + return i +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/reassignment/noifelse.txt b/compiler/testData/diagnostics/tests/reassignment/noifelse.txt new file mode 100644 index 00000000000..349483c63ec --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/noifelse.txt @@ -0,0 +1,3 @@ +package + +internal fun foo(/*0*/ f: kotlin.Boolean): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/reassignment/when.kt b/compiler/testData/diagnostics/tests/reassignment/when.kt new file mode 100644 index 00000000000..3a97cbdc4ca --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/when.kt @@ -0,0 +1,10 @@ +// !DIAGNOSTICS: -UNUSED_VALUE + +fun foo(f: Boolean): Int { + val i: Int + when (f) { + true -> i = 1 + } + i = 3 + return i +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/reassignment/when.txt b/compiler/testData/diagnostics/tests/reassignment/when.txt new file mode 100644 index 00000000000..349483c63ec --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/when.txt @@ -0,0 +1,3 @@ +package + +internal fun foo(/*0*/ f: kotlin.Boolean): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/reassignment/whiletrue.kt b/compiler/testData/diagnostics/tests/reassignment/whiletrue.kt new file mode 100644 index 00000000000..b5867ab389a --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/whiletrue.kt @@ -0,0 +1,11 @@ +// !DIAGNOSTICS: -UNUSED_VALUE + +fun foo(): Int { + val i: Int + var j = 0 + while (true) { + i = ++j + if (j > 5) break + } + return i +} diff --git a/compiler/testData/diagnostics/tests/reassignment/whiletrue.txt b/compiler/testData/diagnostics/tests/reassignment/whiletrue.txt new file mode 100644 index 00000000000..de1d6f17577 --- /dev/null +++ b/compiler/testData/diagnostics/tests/reassignment/whiletrue.txt @@ -0,0 +1,3 @@ +package + +internal fun foo(): kotlin.Int diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index bab6235a5db..1331bb77b62 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -10912,6 +10912,69 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { } } + @TestMetadata("compiler/testData/diagnostics/tests/reassignment") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Reassignment extends AbstractJetDiagnosticsTest { + @TestMetadata("afterfor.kt") + public void testAfterfor() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/reassignment/afterfor.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInReassignment() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/reassignment"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("dowhile.kt") + public void testDowhile() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/reassignment/dowhile.kt"); + doTest(fileName); + } + + @TestMetadata("else.kt") + public void testElse() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/reassignment/else.kt"); + doTest(fileName); + } + + @TestMetadata("foronly.kt") + public void testForonly() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/reassignment/foronly.kt"); + doTest(fileName); + } + + @TestMetadata("if.kt") + public void testIf() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/reassignment/if.kt"); + doTest(fileName); + } + + @TestMetadata("ifelse.kt") + public void testIfelse() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/reassignment/ifelse.kt"); + doTest(fileName); + } + + @TestMetadata("noifelse.kt") + public void testNoifelse() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/reassignment/noifelse.kt"); + doTest(fileName); + } + + @TestMetadata("when.kt") + public void testWhen() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/reassignment/when.kt"); + doTest(fileName); + } + + @TestMetadata("whiletrue.kt") + public void testWhiletrue() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/reassignment/whiletrue.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/recovery") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/j2k/testData/fileOrElement/issues/kt-807.kt b/j2k/testData/fileOrElement/issues/kt-807.kt index 674d51a9eef..9fd22cc6de8 100644 --- a/j2k/testData/fileOrElement/issues/kt-807.kt +++ b/j2k/testData/fileOrElement/issues/kt-807.kt @@ -10,7 +10,7 @@ object FileRead { val fstream = FileInputStream() val `in` = DataInputStream(fstream) val br = BufferedReader(InputStreamReader(`in`)) - val strLine: String + var strLine: String while ((strLine = br.readLine()) != null) { println(strLine) }