diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/AdditionalBuiltInsMembersChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/AdditionalBuiltInsMembersChecker.kt new file mode 100644 index 00000000000..c8d2acd933e --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/AdditionalBuiltInsMembersChecker.kt @@ -0,0 +1,79 @@ +/* + * 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.resolve.jvm.checkers + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageFeatureSettings +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor +import org.jetbrains.kotlin.load.java.isFromBuiltins +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DeclarationChecker +import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker +import org.jetbrains.kotlin.resolve.calls.checkers.elementToReportOn +import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeUniqueAsSequence + +object AdditionalBuiltInsMembersCallChecker : CallChecker { + override fun check( + resolvedCall: ResolvedCall<*>, + context: BasicCallResolutionContext, + languageFeatureSettings: LanguageFeatureSettings + ) { + if (languageFeatureSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)) return + val resultingDescriptor = resolvedCall.resultingDescriptor as? CallableMemberDescriptor ?: return + + reportErrorIfAdditionalBuiltinDescriptor(resultingDescriptor, context.trace, resolvedCall.elementToReportOn) + } +} + +object AdditionalBuiltInsMemberOverrideDeclarationChecker : DeclarationChecker { + override fun check( + declaration: KtDeclaration, + descriptor: DeclarationDescriptor, + diagnosticHolder: DiagnosticSink, + bindingContext: BindingContext, + languageFeatureSettings: LanguageFeatureSettings + ) { + if (languageFeatureSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)) return + val resultingDescriptor = descriptor as? CallableMemberDescriptor ?: return + val overrideKeyword = declaration.modifierList?.getModifier(KtTokens.OVERRIDE_KEYWORD) ?: return + + // TODO: allow to omit 'override' on additional built-ins members + reportErrorIfAdditionalBuiltinDescriptor(resultingDescriptor, diagnosticHolder, overrideKeyword) + } +} + +private fun reportErrorIfAdditionalBuiltinDescriptor( + descriptor: CallableMemberDescriptor, + diagnosticHolder: DiagnosticSink, + reportOn: PsiElement +) { + @Suppress("UNCHECKED_CAST") + val overriddenTree = descriptor.overriddenTreeUniqueAsSequence(useOriginal = true) as Sequence + + if (overriddenTree.any { it.isFromBuiltins() && it is JavaCallableMemberDescriptor }) { + diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(reportOn, LanguageFeature.AdditionalBuiltInsMembers)) + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt index 3b7454dbe4e..281ebaf1222 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt @@ -43,7 +43,8 @@ object JvmPlatformConfigurator : PlatformConfigurator( JvmFieldApplicabilityChecker(), TypeParameterBoundIsNotArrayChecker(), JvmSyntheticApplicabilityChecker(), - StrictfpApplicabilityChecker() + StrictfpApplicabilityChecker(), + AdditionalBuiltInsMemberOverrideDeclarationChecker ), additionalCallCheckers = listOf( @@ -54,7 +55,8 @@ object JvmPlatformConfigurator : PlatformConfigurator( UnsupportedSyntheticCallableReferenceChecker(), SuperCallWithDefaultArgumentsChecker(), MissingDependencyClassChecker(), - ProtectedSyntheticExtensionCallChecker + ProtectedSyntheticExtensionCallChecker, + AdditionalBuiltInsMembersCallChecker ), additionalTypeCheckers = listOf( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/config/LanguageFeatureSettings.kt b/compiler/frontend/src/org/jetbrains/kotlin/config/LanguageFeatureSettings.kt index bcc4faf0716..044745e27db 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/config/LanguageFeatureSettings.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/config/LanguageFeatureSettings.kt @@ -24,7 +24,8 @@ enum class LanguageFeature(val sinceVersion: LanguageVersion) { BoundCallableReferences(KOTLIN_1_1), LocalDelegatedProperties(KOTLIN_1_1), TopLevelSealedInheritance(KOTLIN_1_1), - Coroutines(KOTLIN_1_1) + Coroutines(KOTLIN_1_1), + AdditionalBuiltInsMembers(KOTLIN_1_1) ; companion object { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallChecker.kt index 67e60ac161a..be9525adcbb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallChecker.kt @@ -48,3 +48,6 @@ interface SimpleCallChecker : CallChecker { @Suppress("unused") fun CallChecker.isComputingDeferredType(type: KotlinType) = type is DeferredType && type.isComputing + +val ResolvedCall<*>.elementToReportOn: KtElement + get() = call.calleeExpression ?: call.callElement diff --git a/compiler/testData/diagnostics/testsWithJava8/targetedBuiltIns/unsupportedFeature.kt b/compiler/testData/diagnostics/testsWithJava8/targetedBuiltIns/unsupportedFeature.kt new file mode 100644 index 00000000000..b192bde94c5 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJava8/targetedBuiltIns/unsupportedFeature.kt @@ -0,0 +1,18 @@ +// !LANGUAGE: -AdditionalBuiltInsMembers +// SKIP_TXT + +class A : java.util.ArrayList() { + override fun stream(): java.util.stream.Stream = super.stream() +} + +class A1 : java.util.ArrayList() { + // TODO: should be allowed + fun stream(): java.util.stream.Stream = super.stream() +} + +class B : Throwable("", null, false, false) + +fun foo(x: List) { + x.stream() + java.util.ArrayList().stream() +} diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/DiagnosticsWithJava8TestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/DiagnosticsWithJava8TestGenerated.java index fa55a719f3e..7353ae2ed95 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/DiagnosticsWithJava8TestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/DiagnosticsWithJava8TestGenerated.java @@ -156,5 +156,11 @@ public class DiagnosticsWithJava8TestGenerated extends AbstractDiagnosticsWithFu String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJava8/targetedBuiltIns/stream.kt"); doTest(fileName); } + + @TestMetadata("unsupportedFeature.kt") + public void testUnsupportedFeature() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJava8/targetedBuiltIns/unsupportedFeature.kt"); + doTest(fileName); + } } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/specialBuiltinMembers.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/specialBuiltinMembers.kt index 1fe0acc7754..fc7dd8d4ed8 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/specialBuiltinMembers.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/specialBuiltinMembers.kt @@ -340,8 +340,8 @@ val CallableMemberDescriptor.isFromJava: Boolean get() = propertyIfAccessor is JavaCallableMemberDescriptor && propertyIfAccessor.containingDeclaration is JavaClassDescriptor fun CallableMemberDescriptor.isFromBuiltins(): Boolean { - val fqName = propertyIfAccessor.fqNameOrNull() ?: return false - return fqName.toUnsafe().startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME) && + val fqNameUnsafe = propertyIfAccessor.fqNameUnsafe + return fqNameUnsafe.startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME) && this.module == this.builtIns.builtInsModule }