diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 6f833f0345d..daf76bf6df6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -101,8 +101,9 @@ public interface Errors { // Imports - DiagnosticFactory1 CANNOT_IMPORT_ON_DEMAND_FROM_SINGLETON = DiagnosticFactory1.create(ERROR); - DiagnosticFactory1 CANNOT_BE_IMPORTED = DiagnosticFactory1.create(ERROR); + DiagnosticFactory1 CANNOT_IMPORT_MEMBERS_FROM_SINGLETON = DiagnosticFactory1.create(ERROR); + DiagnosticFactory1 CANNOT_BE_IMPORTED = DiagnosticFactory1.create(ERROR); + DiagnosticFactory0 PACKAGE_CANNOT_BE_IMPORTED = DiagnosticFactory0.create(ERROR); DiagnosticFactory1 CONFLICTING_IMPORT = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 721efe767a6..76c18ac410d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -143,8 +143,9 @@ public class DefaultErrorMessages { MAP.put(LABEL_NAME_CLASH, "There is more than one label with such a name in this scope"); MAP.put(EXPRESSION_EXPECTED_PACKAGE_FOUND, "Expression expected, but a package name found"); - MAP.put(CANNOT_IMPORT_ON_DEMAND_FROM_SINGLETON, "Cannot import-on-demand from object ''{0}''", NAME); - MAP.put(CANNOT_BE_IMPORTED, "Cannot import ''{0}'', functions and properties can be imported only from packages", NAME); + MAP.put(CANNOT_IMPORT_MEMBERS_FROM_SINGLETON, "Cannot import members from object ''{0}''", NAME); + MAP.put(CANNOT_BE_IMPORTED, "Cannot import ''{0}'', functions and properties can be imported only from packages", TO_STRING); + MAP.put(PACKAGE_CANNOT_BE_IMPORTED, "Packages cannot be imported"); MAP.put(CONFLICTING_IMPORT, "Conflicting import, imported name ''{0}'' is ambiguous", STRING); MAP.put(PLATFORM_CLASS_MAPPED_TO_KOTLIN, "This class shouldn''t be used in Kotlin. Use {0} instead.", CLASSES_OR_SEPARATED); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/NewQualifiedExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/NewQualifiedExpressionResolver.kt index 6937ea4cc73..975335a08c4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/NewQualifiedExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/NewQualifiedExpressionResolver.kt @@ -56,42 +56,91 @@ public class NewQualifiedExpressionResolver(val symbolUsageValidator: SymbolUsag if (importDirective.isAllUnder) { val packageOrClassDescriptor = resolveToPackageOrClass(path, moduleDescriptor, trace, shouldBeVisibleFrom) ?: return JetScope.Empty if (packageOrClassDescriptor is ClassDescriptor && packageOrClassDescriptor.kind.isSingleton) { - trace.report(Errors.CANNOT_IMPORT_ON_DEMAND_FROM_SINGLETON.on(lastPart.expression, packageOrClassDescriptor)) + trace.report(Errors.CANNOT_IMPORT_MEMBERS_FROM_SINGLETON.on(lastPart.expression, packageOrClassDescriptor)) // todo report on star } val scope = AllUnderImportsScope() scope.addAllUnderImport(packageOrClassDescriptor) return scope } else { + val aliasName = JetPsiUtil.getAliasName(importDirective) + if (aliasName == null) { // import kotlin. + resolveToPackageOrClass(path, moduleDescriptor, trace, shouldBeVisibleFrom) + return JetScope.Empty + } + val packageOrClassDescriptor = resolveToPackageOrClass(path.subList(0, path.size() - 1), moduleDescriptor, trace, shouldBeVisibleFrom) ?: return JetScope.Empty val descriptors = SmartList() + val lastName = lastPart.name + val location = lastPart.location when (packageOrClassDescriptor) { is PackageViewDescriptor -> { val packageScope = packageOrClassDescriptor.memberScope - descriptors.addIfNotNull(packageScope.getClassifier(lastPart.name, lastPart.location)) - descriptors.addAll(packageScope.getProperties(lastPart.name, lastPart.location)) - descriptors.addAll(packageScope.getFunctions(lastPart.name, lastPart.location)) + descriptors.addIfNotNull(packageScope.getClassifier(lastName, location)) + descriptors.addAll(packageScope.getProperties(lastName, location)) + descriptors.addAll(packageScope.getFunctions(lastName, location)) } + is ClassDescriptor -> { descriptors.addIfNotNull( - packageOrClassDescriptor.unsubstitutedInnerClassesScope.getClassifier(lastPart.name, lastPart.location) + packageOrClassDescriptor.unsubstitutedInnerClassesScope.getClassifier(lastName, location) ) val staticClassScope = packageOrClassDescriptor.staticScope - descriptors.addAll(staticClassScope.getFunctions(lastPart.name, lastPart.location)) - descriptors.addAll(staticClassScope.getProperties(lastPart.name, lastPart.location)) + descriptors.addAll(staticClassScope.getFunctions(lastName, location)) + descriptors.addAll(staticClassScope.getProperties(lastName, location)) } - // todo assert? - else -> return JetScope.Empty - } - storageResult(trace, lastPart.expression, descriptors, shouldBeVisibleFrom) - val aliasName = JetPsiUtil.getAliasName(importDirective) ?: return JetScope.Empty + else -> throw IllegalStateException("Should be class or package: $packageOrClassDescriptor") + } + if (descriptors.isNotEmpty()) { + storageResult(trace, lastPart.expression, descriptors, shouldBeVisibleFrom) + } + else { + tryResolveDescriptorsWhichCannotBeImported(trace, moduleDescriptor, packageOrClassDescriptor, lastPart) + } + return SingleImportScope(aliasName, descriptors) } } + private fun tryResolveDescriptorsWhichCannotBeImported( + trace: BindingTrace, + moduleDescriptor: ModuleDescriptor, + packageOrClassDescriptor: DeclarationDescriptor, + lastPart: QualifierPart + ) { + val descriptors = SmartList() + val lastName = lastPart.name + when (packageOrClassDescriptor) { + is PackageViewDescriptor -> { + val packageDescriptor = moduleDescriptor.getPackage(packageOrClassDescriptor.fqName.child(lastName)) + if (!packageDescriptor.isEmpty()) { + trace.report(Errors.PACKAGE_CANNOT_BE_IMPORTED.on(lastPart.expression)) + descriptors.add(packageOrClassDescriptor) + } + } + + is ClassDescriptor -> { + val memberScope = packageOrClassDescriptor.unsubstitutedMemberScope + descriptors.addAll(memberScope.getFunctions(lastName, lastPart.location)) + descriptors.addAll(memberScope.getProperties(lastName, lastPart.location)) + if (descriptors.isNotEmpty()) { + if (packageOrClassDescriptor.kind.isSingleton) { + trace.report(Errors.CANNOT_IMPORT_MEMBERS_FROM_SINGLETON.on(lastPart.expression, packageOrClassDescriptor)) + } + else { + trace.report(Errors.CANNOT_BE_IMPORTED.on(lastPart.expression, lastName)) + } + } + } + + else -> throw IllegalStateException("Should be class or package: $packageOrClassDescriptor") + } + storageResult(trace, lastPart.expression, descriptors, shouldBeVisibleFrom = null) + } + private fun JetExpression.asQualifierPartList(trace: BindingTrace): List { val result = SmartList() var expression: JetExpression? = this @@ -140,6 +189,9 @@ public class NewQualifiedExpressionResolver(val symbolUsageValidator: SymbolUsag } ?: moduleDescriptor.quickResolveToPackage(path, trace) return path.subList(currentIndex, path.size()).fold(currentDescriptor) { descriptor, qualifierPart -> + // report unresolved reference only for first unresolved qualifier + if (descriptor == null) return@fold null + val nextDescriptor = when (descriptor) { // TODO: support inner classes which captured type parameter from outer class is ClassDescriptor -> diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.java index a3c09d95eed..96c28164553 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.java @@ -322,7 +322,7 @@ public class QualifiedExpressionResolver { // Check for more information and additional errors if (canBeImportedDescriptors.isEmpty()) { assert descriptors.size() >= 1; - trace.report(CANNOT_BE_IMPORTED.on(referenceExpression, descriptors.iterator().next())); + trace.report(CANNOT_BE_IMPORTED.on(referenceExpression, descriptors.iterator().next().getName())); return; } if (canBeImportedDescriptors.size() > 1) { diff --git a/compiler/testData/diagnostics/tests/imports/ExplicitPackageImportsAmbiguity.kt b/compiler/testData/diagnostics/tests/imports/ExplicitPackageImportsAmbiguity.kt index 66c87c9bb00..e9ba08fd835 100644 --- a/compiler/testData/diagnostics/tests/imports/ExplicitPackageImportsAmbiguity.kt +++ b/compiler/testData/diagnostics/tests/imports/ExplicitPackageImportsAmbiguity.kt @@ -11,7 +11,7 @@ class X // FILE: c.kt package c -import a.x -import b.x +import a.x +import b.x class Y : x.X \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/imports/ImportFromObject.kt b/compiler/testData/diagnostics/tests/imports/ImportFromObject.kt index 874db09218c..0898d097819 100644 --- a/compiler/testData/diagnostics/tests/imports/ImportFromObject.kt +++ b/compiler/testData/diagnostics/tests/imports/ImportFromObject.kt @@ -11,7 +11,7 @@ object O { // FILE: b.kt package b -import a.O.* +import a.O.* fun test() { A() diff --git a/compiler/testData/diagnostics/tests/imports/Imports.kt b/compiler/testData/diagnostics/tests/imports/Imports.kt index 903863bb36d..2621129e193 100644 --- a/compiler/testData/diagnostics/tests/imports/Imports.kt +++ b/compiler/testData/diagnostics/tests/imports/Imports.kt @@ -5,16 +5,18 @@ import b.B //class import b.foo //function import b.ext //extension function import b.value //property -import b.C.Companion.bar //function from companion object -import b.C.Companion.cValue //property from companion object +import b.C.Companion.bar //function from companion object +import b.C.Companion.cValue //property from companion object import b.constant.fff //function from val import b.constant.dValue //property from val import b.constant -import b.E.Companion.f //val from companion object +import b.E.Companion.f //val from companion object import smth.illegal import b.C.smth.illegal import b.bar.smth import b.bar.* +import b.unr.unr.unr +import unr.unr.unr fun test(arg: B) { foo(value) @@ -70,7 +72,7 @@ fun bar() {} //FILE:c.kt package c -import c.C.* +import c.C.* object C { fun f() { diff --git a/compiler/testData/diagnostics/tests/imports/MalformedImports.kt b/compiler/testData/diagnostics/tests/imports/MalformedImports.kt index 80e10a47668..1132883cb2e 100644 --- a/compiler/testData/diagnostics/tests/imports/MalformedImports.kt +++ b/compiler/testData/diagnostics/tests/imports/MalformedImports.kt @@ -3,7 +3,7 @@ package test import some. import .some import .kotlin -import kotlin. +import kotlin. import import . import * \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/imports/StarImportFromObject.kt b/compiler/testData/diagnostics/tests/imports/StarImportFromObject.kt index e078b992719..b8dc3285596 100644 --- a/compiler/testData/diagnostics/tests/imports/StarImportFromObject.kt +++ b/compiler/testData/diagnostics/tests/imports/StarImportFromObject.kt @@ -2,21 +2,21 @@ package a import a.A.* import a.A.C -import a.A.C.* -import a.A.D.* -import a.A.C.* +import a.A.C.* +import a.A.D.* +import a.A.C.* import a.A.C.G -import a.A.E.J.* -import a.A.CO.* +import a.A.E.J.* +import a.A.CO.* import a.A.CO import a.B.C.* -import a.B.C.A.* -import a.B.C.D.* +import a.B.C.A.* +import a.B.C.D.* import a.E.* import a.E.E1 -import a.E.E2.* +import a.E.E2.* class A { object C { diff --git a/compiler/testData/diagnostics/tests/imports/SyntaxError.kt b/compiler/testData/diagnostics/tests/imports/SyntaxError.kt new file mode 100644 index 00000000000..7fc5d809454 --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/SyntaxError.kt @@ -0,0 +1,60 @@ +// FILE:a.kt +package a + +val foo = 2 +fun bar() {} + +class B { + val foo = 2 + fun bar() {} + + class C +} + +// FILE:b.kt +package a.b.c + +class D { + class E { + + } +} + + +// FILE:c.kt +import ; +import . +import a. ; +import .a. ; +import .a.b ; +import .a.B ; +import a.B. ; +import a.B.C. ; +import a.B.foo. ; +import a.B.bar. ; +import a.b. ; +import a.b.c. ; +import a.%.b.c. ; +import a.b.c.D. ; +import a.b.c.D.E. ; + +// FILE:d.kt +import +import . +import a. +import .a. +import .a.b +import .a.B +import a.B. as +import a.B. as A +import a.B. +import a.B.C. +import a.B.foo. +import a.B.bar. +import a.b. +import a.b.c. +import a.%.b.c. +import a.b.c.D. +import a.b.c.D.E. + +import a?.b \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/imports/SyntaxError.txt b/compiler/testData/diagnostics/tests/imports/SyntaxError.txt new file mode 100644 index 00000000000..014628a78b6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/SyntaxError.txt @@ -0,0 +1,42 @@ +package + +package a { + public val foo: kotlin.Int = 2 + public fun bar(): kotlin.Unit + + public final class B { + public constructor B() + public final val foo: kotlin.Int = 2 + public final fun bar(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public final class C { + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + package a.b { + + package a.b.c { + + public final class D { + public constructor D() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public final class E { + public constructor E() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + } + } +} diff --git a/compiler/testData/diagnostics/tests/imports/WrongImport.kt b/compiler/testData/diagnostics/tests/imports/WrongImport.kt new file mode 100644 index 00000000000..de9b830ce3b --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/WrongImport.kt @@ -0,0 +1,78 @@ +// FILE:a.kt +package a.b + +// FILE:a.kt +package a + +val foo = object { + fun bar() {} +} + +fun bar() = object { + val foo = 239 +} + +class B { + val foo = object { + fun bar() {} + } + + fun bar() = object { + val foo = 239 + } +} + +object C { + val foo = object { + fun bar() {} + } + + fun bar() = object { + val foo = 239 + } + + class Nested +} + +class D { + companion object { + val foo = object { + fun bar() {} + } + + fun bar() = object { + val foo = 239 + } + } +} + + +// FILE:b.kt +import a +import a.b + +import a.foo +import a.foo.bar +import a.bar +import a.bar.foo + +import a.B.foo +import a.B.foo.bar +import a.B.bar +import a.B.bar.foo + +import a.C.foo +import a.C.foo.bar +import a.C.bar +import a.C.bar.foo +import a.C.Nested + +import a.D.foo +import a.D.foo.bar +import a.D.bar +import a.D.bar.foo + +import a.D.Companion.foo +import a.D.Companion.foo.bar +import a.D.Companion.bar +import a.D.Companion.bar.foo \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/imports/WrongImport.txt b/compiler/testData/diagnostics/tests/imports/WrongImport.txt new file mode 100644 index 00000000000..323653f8d9b --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/WrongImport.txt @@ -0,0 +1,50 @@ +package + +package a { + public val foo: kotlin.Any + public fun bar(): kotlin.Any + + public final class B { + public constructor B() + public final val foo: kotlin.Any + public final fun bar(): kotlin.Any + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public object C { + private constructor C() + public final val foo: kotlin.Any + public final fun bar(): kotlin.Any + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public final class Nested { + public constructor Nested() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + public final class D { + public constructor D() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public companion object Companion { + private constructor Companion() + public final val foo: kotlin.Any + public final fun bar(): kotlin.Any + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + package a.b { + } +} diff --git a/compiler/testData/diagnostics/tests/scopes/kt1080.kt b/compiler/testData/diagnostics/tests/scopes/kt1080.kt index fde50739bc8..4c36bcd2dd8 100644 --- a/compiler/testData/diagnostics/tests/scopes/kt1080.kt +++ b/compiler/testData/diagnostics/tests/scopes/kt1080.kt @@ -8,7 +8,7 @@ import reflect.Const import b.* import d import d.Test -import b.d +import b.d class Some: Test() diff --git a/compiler/testData/diagnostics/tests/scopes/kt900-1.kt b/compiler/testData/diagnostics/tests/scopes/kt900-1.kt index cc9dd509202..ca2f36218eb 100644 --- a/compiler/testData/diagnostics/tests/scopes/kt900-1.kt +++ b/compiler/testData/diagnostics/tests/scopes/kt900-1.kt @@ -2,7 +2,7 @@ package c import c.A.Companion.B -import c.M.* +import c.M.* fun foo() { val b: B = B() diff --git a/compiler/testData/diagnostics/tests/scopes/kt900-2.kt b/compiler/testData/diagnostics/tests/scopes/kt900-2.kt index 32d53af337c..c10844c7963 100644 --- a/compiler/testData/diagnostics/tests/scopes/kt900-2.kt +++ b/compiler/testData/diagnostics/tests/scopes/kt900-2.kt @@ -2,9 +2,9 @@ package d //import from objects before properties resolve -import d.A.* +import d.A.* import d.M.R -import d.M.R.bar +import d.M.R.bar import d.M.T import d.M.Y diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 6f41a04a015..2446881113d 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -6699,11 +6699,23 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("SyntaxError.kt") + public void testSyntaxError() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/imports/SyntaxError.kt"); + doTest(fileName); + } + @TestMetadata("TopLevelClassVsPackage.kt") public void testTopLevelClassVsPackage() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/imports/TopLevelClassVsPackage.kt"); doTest(fileName); } + + @TestMetadata("WrongImport.kt") + public void testWrongImport() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/imports/WrongImport.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/diagnostics/tests/incompleteCode")