Add diagnostic on calling inner classes constructors without receiver

Otherwise there will be just an unresolved reference that doesn't give
any useful information

 #KT-8959 Fixed
This commit is contained in:
Denis Zharkov
2017-02-28 15:28:20 +03:00
parent 1e0ae04aba
commit a7fc32c8da
17 changed files with 133 additions and 37 deletions
@@ -31,6 +31,7 @@ enum class WrongResolutionToClassifier(val message: (Name) -> String) {
INTERFACE_AS_VALUE({ "Interface $it does not have companion object" }), INTERFACE_AS_VALUE({ "Interface $it does not have companion object" }),
INTERFACE_AS_FUNCTION({ "Interface $it does not have constructors" }), INTERFACE_AS_FUNCTION({ "Interface $it does not have constructors" }),
CLASS_AS_VALUE({ "Class $it does not have companion object" }), CLASS_AS_VALUE({ "Class $it does not have companion object" }),
INNER_CLASS_CONSTRUCTOR_NO_RECEIVER({ "Constructor of inner class $it can be called only with receiver of containing class" }),
OBJECT_AS_FUNCTION({ "Function 'invoke()' is not found in object $it" }) OBJECT_AS_FUNCTION({ "Function 'invoke()' is not found in object $it" })
} }
@@ -92,7 +93,11 @@ private fun ErrorCandidateContext.asClassifierCall(asFunction: Boolean) {
when (classifier.kind) { when (classifier.kind) {
ClassKind.INTERFACE -> if (asFunction) INTERFACE_AS_FUNCTION else INTERFACE_AS_VALUE ClassKind.INTERFACE -> if (asFunction) INTERFACE_AS_FUNCTION else INTERFACE_AS_VALUE
ClassKind.OBJECT -> if (asFunction) OBJECT_AS_FUNCTION else return ClassKind.OBJECT -> if (asFunction) OBJECT_AS_FUNCTION else return
ClassKind.CLASS -> if (asFunction) return else CLASS_AS_VALUE ClassKind.CLASS -> when {
asFunction && explicitReceiver is QualifierReceiver? && classifier.isInner -> INNER_CLASS_CONSTRUCTOR_NO_RECEIVER
!asFunction -> CLASS_AS_VALUE
else -> return
}
else -> return else -> return
} }
} }
@@ -41,7 +41,7 @@ fun f() {
C.O C.O
C.O.InO C.O.InO
C.A() C.A()
C.<!UNRESOLVED_REFERENCE!>B<!>() C.<!RESOLUTION_TO_CLASSIFIER!>B<!>()
C.E3.<!UNRESOLVED_REFERENCE!>O_O<!> C.E3.<!UNRESOLVED_REFERENCE!>O_O<!>
C.E3.<!UNRESOLVED_REFERENCE!>G<!>() C.E3.<!UNRESOLVED_REFERENCE!>G<!>()
@@ -8,8 +8,8 @@ class Outer1 {
inner class Inner inner class Inner
class C5 { val b = <!UNRESOLVED_REFERENCE!>Inner<!>() } class C5 { val b = <!RESOLUTION_TO_CLASSIFIER!>Inner<!>() }
class C6(val b: Any = <!UNRESOLVED_REFERENCE!>Inner<!>()) class C6(val b: Any = <!RESOLUTION_TO_CLASSIFIER!>Inner<!>())
inner class C7 { val b = Inner() } inner class C7 { val b = Inner() }
inner class C8(val b: Any = Inner()) inner class C8(val b: Any = Inner())
} }
@@ -18,7 +18,7 @@ class Outer1 {
class Outer2 { class Outer2 {
class Nested { class Nested {
fun foo() = Outer2() fun foo() = Outer2()
fun bar() = <!UNRESOLVED_REFERENCE!>Inner<!>() fun bar() = <!RESOLUTION_TO_CLASSIFIER!>Inner<!>()
} }
inner class Inner { inner class Inner {
fun foo() = Outer2() fun foo() = Outer2()
@@ -0,0 +1,36 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// SKIP_TXT
// FILE: Outer.kt
package abc
class Outer {
inner class Inner() {
constructor(x: Int) : this() {}
}
companion object {
fun baz() {
<!RESOLUTION_TO_CLASSIFIER!>Inner<!>()
<!RESOLUTION_TO_CLASSIFIER!>Inner<!>(1)
}
}
}
fun foo() {
Outer.<!RESOLUTION_TO_CLASSIFIER!>Inner<!>()
Outer.<!RESOLUTION_TO_CLASSIFIER!>Inner<!>(1)
}
// FILE: imported.kt
import abc.Outer
import abc.Outer.Inner
fun bar() {
<!RESOLUTION_TO_CLASSIFIER!>Inner<!>()
<!RESOLUTION_TO_CLASSIFIER!>Inner<!>(1)
with(Outer()) {
Inner()
Inner(1)
}
}
@@ -0,0 +1,43 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// SKIP_TXT
// FILE: Outer.kt
package abc
class Outer {
inner class Inner() {
constructor(x: Int) : this() {}
}
companion object {
fun Inner(x: String) {}
fun baz() {
// Diagnostic here could be better (why can't I call the constructor above?)
Inner(<!NO_VALUE_FOR_PARAMETER!>)<!>
Inner(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>)
Inner("")
}
}
}
fun foo() {
Outer.Inner(<!NO_VALUE_FOR_PARAMETER!>)<!>
Outer.Inner(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>)
Outer.Inner("")
}
// FILE: imported.kt
import abc.Outer
import abc.Outer.Inner
import abc.Outer.Companion.Inner
fun bar() {
Inner(<!NO_VALUE_FOR_PARAMETER!>)<!>
Inner(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>)
Inner("")
with(Outer()) {
Inner()
Inner(1)
Inner("")
}
}
@@ -10,7 +10,7 @@ class Test {
} }
fun more(): InnerClass { fun more(): InnerClass {
val b = <!UNRESOLVED_REFERENCE!>InnerClass<!>() val b = <!RESOLUTION_TO_CLASSIFIER!>InnerClass<!>()
val <!UNUSED_VARIABLE!>testVal<!> = <!UNRESOLVED_REFERENCE!>inClass<!> val <!UNUSED_VARIABLE!>testVal<!> = <!UNRESOLVED_REFERENCE!>inClass<!>
<!UNRESOLVED_REFERENCE!>foo<!>() <!UNRESOLVED_REFERENCE!>foo<!>()
@@ -10,7 +10,7 @@ class Test {
} }
fun more(): InnerClass { fun more(): InnerClass {
val b = <!UNRESOLVED_REFERENCE!>InnerClass<!>() val b = <!RESOLUTION_TO_CLASSIFIER!>InnerClass<!>()
val <!UNUSED_VARIABLE!>testVal<!> = <!UNRESOLVED_REFERENCE!>inClass<!> val <!UNUSED_VARIABLE!>testVal<!> = <!UNRESOLVED_REFERENCE!>inClass<!>
<!UNRESOLVED_REFERENCE!>foo<!>() <!UNRESOLVED_REFERENCE!>foo<!>()
@@ -11,7 +11,7 @@ class Outer {
fun f1() = Outer() fun f1() = Outer()
fun f2() = Outer.Nested() fun f2() = Outer.Nested()
fun f3() = Outer.Nested.NestedNested() fun f3() = Outer.Nested.NestedNested()
fun f4() = Outer.<!UNRESOLVED_REFERENCE!>Inner<!>() fun f4() = Outer.<!RESOLUTION_TO_CLASSIFIER!>Inner<!>()
fun f5() = Outer.Inner.<!UNRESOLVED_REFERENCE!>InnerInner<!>() fun f5() = Outer.Inner.<!RESOLUTION_TO_CLASSIFIER!>InnerInner<!>()
fun f6() = Outer().Inner() fun f6() = Outer().Inner()
fun f7() = Outer().Inner().InnerInner() fun f7() = Outer().Inner().InnerInner()
+1 -1
View File
@@ -12,5 +12,5 @@ class C {
fun f() { fun f() {
<!RESOLUTION_TO_CLASSIFIER!>TestInterface<!>() <!RESOLUTION_TO_CLASSIFIER!>TestInterface<!>()
C.<!UNRESOLVED_REFERENCE!>I<!>() C.<!RESOLUTION_TO_CLASSIFIER!>I<!>()
} }
@@ -4,7 +4,7 @@ class A(
n: Nested = foo(), n: Nested = foo(),
n2: Nested = Nested(), n2: Nested = Nested(),
inn: Inner = null!!, inn: Inner = null!!,
inn2: Inner = <!UNRESOLVED_REFERENCE!>Inner<!>(), inn2: Inner = <!RESOLUTION_TO_CLASSIFIER!>Inner<!>(),
i: Interface = null!!, i: Interface = null!!,
c: Int = CONST, c: Int = CONST,
cc: Int = Companion.CONST, cc: Int = Companion.CONST,
@@ -17,7 +17,7 @@ open class S(
class A : I by S( class A : I by S(
foo(), foo(),
Nested(), Nested(),
<!UNRESOLVED_REFERENCE!>Inner<!>(), <!RESOLUTION_TO_CLASSIFIER!>Inner<!>(),
CONST, CONST,
Companion.CONST, Companion.CONST,
Nested.CONST, Nested.CONST,
@@ -15,7 +15,7 @@ open class S(
class A : S ( class A : S (
foo(), foo(),
Nested(), Nested(),
<!UNRESOLVED_REFERENCE!>Inner<!>(), <!RESOLUTION_TO_CLASSIFIER!>Inner<!>(),
CONST, CONST,
Companion.CONST, Companion.CONST,
Nested.CONST, Nested.CONST,
@@ -33,10 +33,10 @@ class E: A() {
object Z { object Z {
init { init {
<!UNRESOLVED_REFERENCE!>B<!>().<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>foo<!>() <!RESOLUTION_TO_CLASSIFIER!>B<!>().<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>foo<!>()
<!UNRESOLVED_REFERENCE!>B<!>().<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>bar<!>() <!RESOLUTION_TO_CLASSIFIER!>B<!>().<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>bar<!>()
<!UNRESOLVED_REFERENCE!>D<!>() <!RESOLUTION_TO_CLASSIFIER!>D<!>()
C() C()
} }
} }
@@ -58,7 +58,7 @@ class F: A() {
companion object { companion object {
init { init {
B().fas() B().fas()
<!UNRESOLVED_REFERENCE!>D<!>().<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>f<!>() <!RESOLUTION_TO_CLASSIFIER!>D<!>().<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>f<!>()
} }
} }
} }
@@ -46,7 +46,7 @@ class Y: B() {
init { init {
B_() B_()
B.<!UNRESOLVED_REFERENCE!>B_<!>() B.<!RESOLUTION_TO_CLASSIFIER!>B_<!>()
Y.<!UNRESOLVED_REFERENCE!>B_<!>() Y.<!UNRESOLVED_REFERENCE!>B_<!>()
B_S() B_S()
@@ -59,7 +59,7 @@ class Y: B() {
val b_s: B_S = null!! val b_s: B_S = null!!
init { init {
<!UNRESOLVED_REFERENCE!>B_<!>() <!RESOLUTION_TO_CLASSIFIER!>B_<!>()
B_S() B_S()
} }
} }
@@ -83,7 +83,7 @@ class Z: C() {
init { init {
<!UNRESOLVED_REFERENCE!>A_S<!>() <!UNRESOLVED_REFERENCE!>A_S<!>()
<!UNRESOLVED_REFERENCE!>B_<!>() <!RESOLUTION_TO_CLASSIFIER!>B_<!>()
B_S() B_S()
} }
} }
@@ -36,7 +36,7 @@ public class F extends D {
class X: D() { class X: D() {
init { init {
B_() B_()
B.<!UNRESOLVED_REFERENCE!>B_<!>() B.<!RESOLUTION_TO_CLASSIFIER!>B_<!>()
C.<!UNRESOLVED_REFERENCE!>B_<!>() C.<!UNRESOLVED_REFERENCE!>B_<!>()
D.<!UNRESOLVED_REFERENCE!>B_<!>() D.<!UNRESOLVED_REFERENCE!>B_<!>()
X.<!UNRESOLVED_REFERENCE!>B_<!>() X.<!UNRESOLVED_REFERENCE!>B_<!>()
@@ -27,7 +27,7 @@ class Outer {
typealias Test5 = Outer.Inner typealias Test5 = Outer.Inner
val test5 = <!UNRESOLVED_REFERENCE!>Test5<!>() val test5 = <!UNRESOLVED_REFERENCE!>Test5<!>()
val test5a = Outer.<!UNRESOLVED_REFERENCE!>Inner<!>() val test5a = Outer.<!RESOLUTION_TO_CLASSIFIER!>Inner<!>()
val test5b = Outer.<!UNRESOLVED_REFERENCE!>TestInner<!>() val test5b = Outer.<!UNRESOLVED_REFERENCE!>TestInner<!>()
val test5c = Outer().<!UNRESOLVED_REFERENCE!>TestInner<!>() val test5c = Outer().<!UNRESOLVED_REFERENCE!>TestInner<!>()
val test5d = Outer().Inner() val test5d = Outer().Inner()
@@ -11347,6 +11347,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("innerConstructorsFromQualifiers.kt")
public void testInnerConstructorsFromQualifiers() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inner/innerConstructorsFromQualifiers.kt");
doTest(fileName);
}
@TestMetadata("innerConstructorsFromQualifiersWithIrrelevantCandidate.kt")
public void testInnerConstructorsFromQualifiersWithIrrelevantCandidate() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inner/innerConstructorsFromQualifiersWithIrrelevantCandidate.kt");
doTest(fileName);
}
@TestMetadata("innerErrorForClassObjects.kt") @TestMetadata("innerErrorForClassObjects.kt")
public void testInnerErrorForClassObjects() throws Exception { public void testInnerErrorForClassObjects() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inner/innerErrorForClassObjects.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inner/innerErrorForClassObjects.kt");