diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/noImpl.kt b/compiler/testData/diagnostics/testsWithJsStdLib/noImpl.kt new file mode 100644 index 00000000000..6add08518a7 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/noImpl.kt @@ -0,0 +1,29 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER, -UNREACHABLE_CODE + +val prop: String = noImpl + +val prop2: String + get() = noImpl + +fun foo(x: Int, y: String = noImpl) { + println("Hello") + println("world") + + object { + fun bar(): Any = noImpl + } + + listOf() + .map { noImpl } + .filter(fun(x: String): Boolean { noImpl }) + + noImpl +} + +open class A(val x: Int) + +open class B() : A(noImpl) { + constructor(y: String) : this() + + constructor(y: String, z: String) : this(y + z + noImpl) +} diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/noImpl.txt b/compiler/testData/diagnostics/testsWithJsStdLib/noImpl.txt new file mode 100644 index 00000000000..d7294493b1b --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/noImpl.txt @@ -0,0 +1,23 @@ +package + +public val prop: kotlin.String +public val prop2: kotlin.String +public fun foo(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.String = ...): kotlin.Unit + +public open class A { + public constructor A(/*0*/ x: kotlin.Int) + public final val x: kotlin.Int + 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 open class B : A { + public constructor B() + public constructor B(/*0*/ y: kotlin.String) + public constructor B(/*0*/ y: kotlin.String, /*1*/ z: kotlin.String) + public final override /*1*/ /*fake_override*/ val x: kotlin.Int + 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/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java index 92cfeb648a0..5116c5aa7cf 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java @@ -48,6 +48,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes doTest(fileName); } + @TestMetadata("noImpl.kt") + public void testNoImpl() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/noImpl.kt"); + doTest(fileName); + } + @TestMetadata("runtimeAnnotations.kt") public void testRuntimeAnnotations() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/runtimeAnnotations.kt"); diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt index e18bc19e902..b7dca3ead2e 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt @@ -42,7 +42,12 @@ object JsPlatformConfigurator : PlatformConfigurator( JsDynamicDeclarationChecker, HeaderImplDeclarationChecker() ), - additionalCallCheckers = listOf(ReifiedTypeParameterSubstitutionChecker(), JsModuleCallChecker, JsDynamicCallChecker), + additionalCallCheckers = listOf( + ReifiedTypeParameterSubstitutionChecker(), + JsModuleCallChecker, + JsDynamicCallChecker, + JsNoImplCallChecker + ), additionalTypeCheckers = listOf(), additionalClassifierUsageCheckers = listOf(), additionalAnnotationCheckers = listOf(), diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/DefaultErrorMessagesJs.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/DefaultErrorMessagesJs.kt index 5c69f21aa78..77ce6572543 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/DefaultErrorMessagesJs.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/DefaultErrorMessagesJs.kt @@ -94,6 +94,7 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy { put(ErrorsJs.EXTERNAL_ANONYMOUS_INITIALIZER, "Anonymous initializer is not allowed in external classes") put(ErrorsJs.EXTERNAL_ENUM_ENTRY_WITH_BODY, "Entry of external enum class can't have body") put(ErrorsJs.EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER, "External class constructor cannot have a property parameter") + put(ErrorsJs.CALL_TO_NO_IMPL_FROM_NON_EXTERNAL_DECLARATION, "This property can only be used from external declarations") this } diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java index 0384baeaf70..d1c72ae9b01 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java @@ -97,6 +97,7 @@ public interface ErrorsJs { DiagnosticFactory0 EXTERNAL_ANONYMOUS_INITIALIZER = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 EXTERNAL_ENUM_ENTRY_WITH_BODY = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 CALL_TO_NO_IMPL_FROM_NON_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR); @SuppressWarnings("UnusedDeclaration") Object _initializer = new Object() { diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNoImplCallChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNoImplCallChecker.kt new file mode 100644 index 00000000000..63f27471963 --- /dev/null +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNoImplCallChecker.kt @@ -0,0 +1,36 @@ +/* + * 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.js.resolve.diagnostics.JsExternalChecker.NO_IMPL_PROPERTY_NAME +import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils +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.descriptorUtil.fqNameUnsafe + +object JsNoImplCallChecker : CallChecker { + override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { + if (resolvedCall.resultingDescriptor.fqNameUnsafe != NO_IMPL_PROPERTY_NAME) return + + val ownerDescriptor = context.scope.ownerDescriptor + if (!AnnotationsUtils.isNativeObject(ownerDescriptor) && !AnnotationsUtils.isPredefinedObject(ownerDescriptor)) { + context.trace.report(ErrorsJs.CALL_TO_NO_IMPL_FROM_NON_EXTERNAL_DECLARATION.on(reportOn)) + } + } +}