diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 96a4d1adecc..11306ec0a52 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -916,16 +916,6 @@ public class JetControlFlowProcessor { JetObjectDeclaration declaration = expression.getObjectDeclaration(); generateInstructions(declaration, context); - List declarations = declaration.getDeclarations(); - List functions = Lists.newArrayList(); - for (JetDeclaration localDeclaration : declarations) { - if (!(localDeclaration instanceof JetProperty) && !(localDeclaration instanceof JetClassInitializer)) { - functions.add(localDeclaration); - } - } - for (JetDeclaration function : functions) { - generateInstructions(function, context); - } builder.createAnonymousObject(expression); } @@ -961,6 +951,13 @@ public class JetControlFlowProcessor { generateInstructions(specifier, context); } List declarations = classOrObject.getDeclarations(); + if (JetPsiUtil.isLocal(classOrObject)) { + for (JetDeclaration declaration : declarations) { + generateInstructions(declaration, context); + } + return; + } + //For top-level and inner classes and objects functions are collected and checked separately. for (JetDeclaration declaration : declarations) { if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) { generateInstructions(declaration, context); diff --git a/compiler/testData/cfg/localClass.instructions b/compiler/testData/cfg/localClass.instructions new file mode 100644 index 00000000000..394341737f9 --- /dev/null +++ b/compiler/testData/cfg/localClass.instructions @@ -0,0 +1,113 @@ +== f == +fun f() { + class LocalClass() { + fun f() { + val x = "" + + fun loc() { + val x3 = "" + } + } + } +} +--------------------- +L0: + + mark({ class LocalClass() { fun f() { val x = "" fun loc() { val x3 = "" } } } }) + jmp?(L2) NEXT:[, d(fun f() { val x = "" fun loc() { val x3 = "" } })] + d(fun f() { val x = "" fun loc() { val x3 = "" } }) NEXT:[] +L1: +L2: + NEXT:[] PREV:[jmp?(L2)] +error: + PREV:[] +sink: + PREV:[, , d(fun f() { val x = "" fun loc() { val x3 = "" } })] +L3: + + mark({ val x = "" fun loc() { val x3 = "" } }) + v(val x = "") + mark("") + r("") + w(x) + jmp?(L5) NEXT:[, d(fun loc() { val x3 = "" })] + d(fun loc() { val x3 = "" }) NEXT:[] +L4: +L5: + NEXT:[] PREV:[jmp?(L5)] +error: + PREV:[] +sink: + PREV:[, , d(fun loc() { val x3 = "" })] +L6: + + mark({ val x3 = "" }) + v(val x3 = "") + mark("") + r("") + w(x3) +L7: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== f == +fun f() { + val x = "" + + fun loc() { + val x3 = "" + } + } +--------------------- +L3: + + mark({ val x = "" fun loc() { val x3 = "" } }) + v(val x = "") + mark("") + r("") + w(x) + jmp?(L5) NEXT:[, d(fun loc() { val x3 = "" })] + d(fun loc() { val x3 = "" }) NEXT:[] +L4: +L5: + NEXT:[] PREV:[jmp?(L5)] +error: + PREV:[] +sink: + PREV:[, , d(fun loc() { val x3 = "" })] +L6: + + mark({ val x3 = "" }) + v(val x3 = "") + mark("") + r("") + w(x3) +L7: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== loc == +fun loc() { + val x3 = "" + } +--------------------- +L6: + + mark({ val x3 = "" }) + v(val x3 = "") + mark("") + r("") + w(x3) +L7: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/localClass.kt b/compiler/testData/cfg/localClass.kt new file mode 100644 index 00000000000..f68a2ac125c --- /dev/null +++ b/compiler/testData/cfg/localClass.kt @@ -0,0 +1,11 @@ +fun f() { + class LocalClass() { + fun f() { + val x = "" + + fun loc() { + val x3 = "" + } + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt3501.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt3501.kt new file mode 100644 index 00000000000..bb9731dc3a4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt3501.kt @@ -0,0 +1,9 @@ +//KT-3501 Variable/parameter is highlighted as unused if it is used in member of local class + +fun f(p: String) { // "p" is marked as unused + class LocalClass { + fun f() { + p + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/localClasses.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/localClasses.kt new file mode 100644 index 00000000000..6c3890bcd69 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/localClasses.kt @@ -0,0 +1,26 @@ +package f + +fun f() { + class LocalClass() { + { + val x1 = "" // ok: unused + + fun loc1(): Int { + val x1_ = "" // ok: unused + } + } + + fun f() { + val x2 = "" // error: should be UNUSED_VARIABLE + + fun loc2(): Int { + val x2_ = "" // error: should be UNUSED_VARIABLE + } + } + + val v: String + get() { + val x3 = "" // ok: unused + } + } +} diff --git a/compiler/testData/diagnostics/tests/inner/referenceToSelfInLocal.kt b/compiler/testData/diagnostics/tests/inner/referenceToSelfInLocal.kt index e49bfee8248..1b8965f90a5 100644 --- a/compiler/testData/diagnostics/tests/inner/referenceToSelfInLocal.kt +++ b/compiler/testData/diagnostics/tests/inner/referenceToSelfInLocal.kt @@ -7,7 +7,7 @@ fun f() { } fun member() { - val x: MyClass = MyClass() + val x: MyClass = MyClass() } } diff --git a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java index dfd86729115..bc5fd592ad9 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java @@ -157,6 +157,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest { doTest("compiler/testData/cfg/LazyBooleans.kt"); } + @TestMetadata("localClass.kt") + public void testLocalClass() throws Exception { + doTest("compiler/testData/cfg/localClass.kt"); + } + @TestMetadata("LocalDeclarations.kt") public void testLocalDeclarations() throws Exception { doTest("compiler/testData/cfg/LocalDeclarations.kt"); diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 7f6ff10850d..19c9c44656f 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1608,6 +1608,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt3444.kt"); } + @TestMetadata("kt3501.kt") + public void testKt3501() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt3501.kt"); + } + @TestMetadata("kt510.kt") public void testKt510() throws Exception { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt510.kt"); @@ -1643,6 +1648,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt897.kt"); } + @TestMetadata("localClasses.kt") + public void testLocalClasses() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/localClasses.kt"); + } + @TestMetadata("propertiesOrderInPackage.kt") public void testPropertiesOrderInPackage() throws Exception { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/propertiesOrderInPackage.kt"); diff --git a/idea/testData/checker/infos/CapturedInInlinedClosure.kt b/idea/testData/checker/infos/CapturedInInlinedClosure.kt index 558b3446c9a..40f7c432d11 100644 --- a/idea/testData/checker/infos/CapturedInInlinedClosure.kt +++ b/idea/testData/checker/infos/CapturedInInlinedClosure.kt @@ -58,7 +58,7 @@ fun localFunctionAndClass() { } } - val v = 1 // erroneous "unused warning" is caused by KT-3501 + val v = 1 class LocalClass { fun f() { run {