diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToModule.kt b/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToModule.kt index e87532642e3..fc7ae91932c 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToModule.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToModule.kt @@ -39,5 +39,4 @@ fun box() { baz() } -// TODO: fix and uncomment -// external class DerivedB : B< !> \ No newline at end of file +external class DerivedB : B \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToModule.txt b/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToModule.txt index 8c4a6a6bcd3..9db3570a9f2 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToModule.txt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToModule.txt @@ -28,6 +28,14 @@ package package bar { public fun box(): kotlin.Unit + + public external final class DerivedB : foo.B { + public constructor DerivedB() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final override /*1*/ /*fake_override*/ fun foo(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } } package foo { diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToNonModule.kt b/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToNonModule.kt index 8914b077c72..355c5f32598 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToNonModule.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToNonModule.kt @@ -33,5 +33,4 @@ fun box() { bar() } -// TODO: fix and uncomment -// external class DerivedB : B< !> \ No newline at end of file +external class DerivedB : B \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToNonModule.txt b/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToNonModule.txt index 795baa56d40..697330909bc 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToNonModule.txt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/module/wrongCallToNonModule.txt @@ -2,6 +2,14 @@ package package bar { public fun box(): kotlin.Unit + + public external final class DerivedB : foo.B { + public constructor DerivedB() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final override /*1*/ /*fake_override*/ fun foo(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } } package foo { diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsModuleCallChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsModuleCallChecker.kt index e42b129c5ed..1dd1632f205 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsModuleCallChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsModuleCallChecker.kt @@ -18,47 +18,18 @@ package org.jetbrains.kotlin.js.resolve.diagnostics import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor -import org.jetbrains.kotlin.js.resolve.MODULE_KIND -import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.scopes.receivers.ClassValueReceiver -import org.jetbrains.kotlin.serialization.js.ModuleKind object JsModuleCallChecker : CallChecker { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { + val callee = extractModuleCallee(resolvedCall) ?: return val bindingContext = context.trace.bindingContext val containingDescriptor = context.scope.ownerDescriptor - val module = DescriptorUtils.getContainingModule(containingDescriptor) - val moduleKind = bindingContext[MODULE_KIND, module] ?: return - - val callee = findRoot(extractModuleCallee(resolvedCall) ?: return) - if (!AnnotationsUtils.isNativeObject(callee)) return - - val callToModule = AnnotationsUtils.getModuleName(callee) != null || - AnnotationsUtils.getFileModuleName(bindingContext, callee) != null - val callToNonModule = AnnotationsUtils.isNonModule(callee) || AnnotationsUtils.isFromNonModuleFile(bindingContext, callee) - - if (moduleKind == ModuleKind.UMD) { - if (!callToNonModule && callToModule || callToNonModule && !callToModule) { - context.trace.report(ErrorsJs.CALL_FROM_UMD_MUST_BE_JS_MODULE_AND_JS_NON_MODULE.on(reportOn)) - } - } - else { - if (moduleKind == ModuleKind.PLAIN) { - if (!callToNonModule && callToModule) { - context.trace.report(ErrorsJs.CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM.on(reportOn)) - } - } - else { - if (!callToModule && callToNonModule) { - context.trace.report(ErrorsJs.CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM.on(reportOn)) - } - } - } + checkJsModuleUsage(bindingContext, context.trace, containingDescriptor, callee, reportOn) } private fun extractModuleCallee(call: ResolvedCall<*>): DeclarationDescriptor? { @@ -70,9 +41,4 @@ object JsModuleCallChecker : CallChecker { return null } - - private fun findRoot(callee: DeclarationDescriptor) = - generateSequence(callee) { it.containingDeclaration } - .takeWhile { it !is PackageFragmentDescriptor } - .last() } diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsModuleCheckUtil.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsModuleCheckUtil.kt new file mode 100644 index 00000000000..18d544d4128 --- /dev/null +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsModuleCheckUtil.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.js.resolve.diagnostics + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.js.resolve.MODULE_KIND +import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.serialization.js.ModuleKind + +fun checkJsModuleUsage( + bindingContext: BindingContext, + diagnosticSink: DiagnosticSink, + container: DeclarationDescriptor, + callee: DeclarationDescriptor, + reportOn: PsiElement +) { + val module = DescriptorUtils.getContainingModule(container) + val moduleKind = bindingContext[MODULE_KIND, module] ?: return + val calleeRootContainer = findRoot(callee) + + val callToModule = AnnotationsUtils.getModuleName(calleeRootContainer) != null || + AnnotationsUtils.getFileModuleName(bindingContext, calleeRootContainer) != null + val callToNonModule = AnnotationsUtils.isNonModule(calleeRootContainer) || + AnnotationsUtils.isFromNonModuleFile(bindingContext, calleeRootContainer) + + if (moduleKind == ModuleKind.UMD) { + if (!callToNonModule && callToModule || callToNonModule && !callToModule) { + diagnosticSink.report(ErrorsJs.CALL_FROM_UMD_MUST_BE_JS_MODULE_AND_JS_NON_MODULE.on(reportOn)) + } + } + else { + if (moduleKind == ModuleKind.PLAIN) { + if (!callToNonModule && callToModule) { + diagnosticSink.report(ErrorsJs.CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM.on(reportOn)) + } + } + else { + if (!callToModule && callToNonModule) { + diagnosticSink.report(ErrorsJs.CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM.on(reportOn)) + } + } + } +} + +private fun findRoot(callee: DeclarationDescriptor) = generateSequence(callee) { it.containingDeclaration } + .takeWhile { it !is PackageFragmentDescriptor } + .last() \ No newline at end of file diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsModuleChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsModuleChecker.kt index 35c11911d9f..de39a0025b1 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsModuleChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsModuleChecker.kt @@ -16,14 +16,16 @@ package org.jetbrains.kotlin.js.resolve.diagnostics +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils +import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker -import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny object JsModuleChecker : SimpleDeclarationChecker { override fun check( @@ -32,6 +34,7 @@ object JsModuleChecker : SimpleDeclarationChecker { diagnosticHolder: DiagnosticSink, bindingContext: BindingContext ) { + checkSuperClass(bindingContext, diagnosticHolder, descriptor, declaration) if (AnnotationsUtils.getModuleName(descriptor) == null && !AnnotationsUtils.isNonModule(descriptor)) return if (descriptor is PropertyDescriptor && descriptor.isVar) { @@ -48,4 +51,20 @@ object JsModuleChecker : SimpleDeclarationChecker { diagnosticHolder.report(ErrorsJs.NESTED_JS_MODULE_PROHIBITED.on(declaration)) } } + + private fun checkSuperClass( + bindingContext: BindingContext, + diagnosticHolder: DiagnosticSink, + descriptor: DeclarationDescriptor, + declaration: KtDeclaration + ) { + if (descriptor !is ClassDescriptor) return + val superClass = descriptor.getSuperClassNotAny() ?: return + + val psi = (declaration as KtClassOrObject).superTypeListEntries.firstOrNull { entry -> + bindingContext[BindingContext.TYPE, entry.typeReference]?.constructor?.declarationDescriptor == superClass + } + + checkJsModuleUsage(bindingContext, diagnosticHolder, descriptor, superClass, psi ?: declaration) + } }