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_FUNCTION({ "Interface $it does not have constructors" }),
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" })
}
@@ -92,7 +93,11 @@ private fun ErrorCandidateContext.asClassifierCall(asFunction: Boolean) {
when (classifier.kind) {
ClassKind.INTERFACE -> if (asFunction) INTERFACE_AS_FUNCTION else INTERFACE_AS_VALUE
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
}
}
@@ -41,8 +41,8 @@ fun f() {
C.O
C.O.InO
C.A()
C.<!UNRESOLVED_REFERENCE!>B<!>()
C.<!RESOLUTION_TO_CLASSIFIER!>B<!>()
C.E3.<!UNRESOLVED_REFERENCE!>O_O<!>
C.E3.<!UNRESOLVED_REFERENCE!>G<!>()
}
}
@@ -1,15 +1,15 @@
class Outer1 {
class Nested
class C1 { val b = Nested() }
class C2(val b: Any = Nested())
inner class C3 { val b = Nested() }
inner class C4(val b: Any = Nested())
inner class Inner
class C5 { val b = <!UNRESOLVED_REFERENCE!>Inner<!>() }
class C6(val b: Any = <!UNRESOLVED_REFERENCE!>Inner<!>())
class C5 { val b = <!RESOLUTION_TO_CLASSIFIER!>Inner<!>() }
class C6(val b: Any = <!RESOLUTION_TO_CLASSIFIER!>Inner<!>())
inner class C7 { val b = Inner() }
inner class C8(val b: Any = Inner())
}
@@ -18,15 +18,15 @@ class Outer1 {
class Outer2 {
class Nested {
fun foo() = Outer2()
fun bar() = <!UNRESOLVED_REFERENCE!>Inner<!>()
fun bar() = <!RESOLUTION_TO_CLASSIFIER!>Inner<!>()
}
inner class Inner {
fun foo() = Outer2()
fun bar() = Nested()
}
fun foo() {
Nested()
Inner()
}
}
}
@@ -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 {
val b = <!UNRESOLVED_REFERENCE!>InnerClass<!>()
val b = <!RESOLUTION_TO_CLASSIFIER!>InnerClass<!>()
val <!UNUSED_VARIABLE!>testVal<!> = <!UNRESOLVED_REFERENCE!>inClass<!>
<!UNRESOLVED_REFERENCE!>foo<!>()
@@ -23,4 +23,4 @@ class Test {
fun foo() {}
open inner class InnerClass
}
}
@@ -10,7 +10,7 @@ class Test {
}
fun more(): InnerClass {
val b = <!UNRESOLVED_REFERENCE!>InnerClass<!>()
val b = <!RESOLUTION_TO_CLASSIFIER!>InnerClass<!>()
val <!UNUSED_VARIABLE!>testVal<!> = <!UNRESOLVED_REFERENCE!>inClass<!>
<!UNRESOLVED_REFERENCE!>foo<!>()
@@ -24,4 +24,4 @@ class Test {
}
open inner class InnerClass
}
}
@@ -2,7 +2,7 @@ class Outer {
class Nested {
class NestedNested
}
inner class Inner {
inner class InnerInner
}
@@ -11,7 +11,7 @@ class Outer {
fun f1() = Outer()
fun f2() = Outer.Nested()
fun f3() = Outer.Nested.NestedNested()
fun f4() = Outer.<!UNRESOLVED_REFERENCE!>Inner<!>()
fun f5() = Outer.Inner.<!UNRESOLVED_REFERENCE!>InnerInner<!>()
fun f4() = Outer.<!RESOLUTION_TO_CLASSIFIER!>Inner<!>()
fun f5() = Outer.Inner.<!RESOLUTION_TO_CLASSIFIER!>InnerInner<!>()
fun f6() = Outer().Inner()
fun f7() = Outer().Inner().InnerInner()
fun f7() = Outer().Inner().InnerInner()
+2 -2
View File
@@ -12,5 +12,5 @@ class C {
fun f() {
<!RESOLUTION_TO_CLASSIFIER!>TestInterface<!>()
C.<!UNRESOLVED_REFERENCE!>I<!>()
}
C.<!RESOLUTION_TO_CLASSIFIER!>I<!>()
}
@@ -4,7 +4,7 @@ class A(
n: Nested = foo(),
n2: Nested = Nested(),
inn: Inner = null!!,
inn2: Inner = <!UNRESOLVED_REFERENCE!>Inner<!>(),
inn2: Inner = <!RESOLUTION_TO_CLASSIFIER!>Inner<!>(),
i: Interface = null!!,
c: Int = CONST,
cc: Int = Companion.CONST,
@@ -17,7 +17,7 @@ open class S(
class A : I by S(
foo(),
Nested(),
<!UNRESOLVED_REFERENCE!>Inner<!>(),
<!RESOLUTION_TO_CLASSIFIER!>Inner<!>(),
CONST,
Companion.CONST,
Nested.CONST,
@@ -15,7 +15,7 @@ open class S(
class A : S (
foo(),
Nested(),
<!UNRESOLVED_REFERENCE!>Inner<!>(),
<!RESOLUTION_TO_CLASSIFIER!>Inner<!>(),
CONST,
Companion.CONST,
Nested.CONST,
@@ -33,10 +33,10 @@ class E: A() {
object Z {
init {
<!UNRESOLVED_REFERENCE!>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!>foo<!>()
<!RESOLUTION_TO_CLASSIFIER!>B<!>().<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>bar<!>()
<!UNRESOLVED_REFERENCE!>D<!>()
<!RESOLUTION_TO_CLASSIFIER!>D<!>()
C()
}
}
@@ -58,7 +58,7 @@ class F: A() {
companion object {
init {
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 {
B_()
B.<!UNRESOLVED_REFERENCE!>B_<!>()
B.<!RESOLUTION_TO_CLASSIFIER!>B_<!>()
Y.<!UNRESOLVED_REFERENCE!>B_<!>()
B_S()
@@ -59,7 +59,7 @@ class Y: B() {
val b_s: B_S = null!!
init {
<!UNRESOLVED_REFERENCE!>B_<!>()
<!RESOLUTION_TO_CLASSIFIER!>B_<!>()
B_S()
}
}
@@ -83,8 +83,8 @@ class Z: C() {
init {
<!UNRESOLVED_REFERENCE!>A_S<!>()
<!UNRESOLVED_REFERENCE!>B_<!>()
<!RESOLUTION_TO_CLASSIFIER!>B_<!>()
B_S()
}
}
}
}
@@ -36,7 +36,7 @@ public class F extends D {
class X: D() {
init {
B_()
B.<!UNRESOLVED_REFERENCE!>B_<!>()
B.<!RESOLUTION_TO_CLASSIFIER!>B_<!>()
C.<!UNRESOLVED_REFERENCE!>B_<!>()
D.<!UNRESOLVED_REFERENCE!>B_<!>()
X.<!UNRESOLVED_REFERENCE!>B_<!>()
@@ -79,4 +79,4 @@ class Y: F() {
F.<!UNRESOLVED_REFERENCE!>E_S<!>()
Y.<!UNRESOLVED_REFERENCE!>E_S<!>()
}
}
}
@@ -27,8 +27,8 @@ class Outer {
typealias Test5 = Outer.Inner
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 test5c = Outer().<!UNRESOLVED_REFERENCE!>TestInner<!>()
val test5d = Outer().Inner()
val test5e = Outer().Test5()
val test5e = Outer().Test5()
@@ -11347,6 +11347,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
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")
public void testInnerErrorForClassObjects() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inner/innerErrorForClassObjects.kt");