Introduce OptionalExpectation for annotations missing on some platforms
This commits adds a new annotation OptionalExpectation to the standard library, which is experimental. To enable its usage, either pass '-Xuse-experimental=kotlin.ExperimentalMultiplatform' as a compiler argument, or '-Xuse-experimental=kotlin.Experimental' and also annotate each usage with `@UseExperimental(ExperimentalMultiplatform::class)` #KT-18882 Fixed
This commit is contained in:
@@ -300,6 +300,10 @@ public abstract class AnnotationCodegen {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (classDescriptor.isExpect()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
innerClassConsumer.addInnerClassInfoFromAnnotation(classDescriptor);
|
||||
|
||||
String asmTypeDescriptor = typeMapper.mapType(annotationDescriptor.getType()).getDescriptor();
|
||||
|
||||
@@ -619,6 +619,9 @@ public interface Errors {
|
||||
DiagnosticFactory2.create(ERROR, ACTUAL_DECLARATION_NAME);
|
||||
DiagnosticFactory0<KtNamedDeclaration> ACTUAL_MISSING = DiagnosticFactory0.create(ERROR, ACTUAL_DECLARATION_NAME);
|
||||
|
||||
DiagnosticFactory0<PsiElement> OPTIONAL_EXPECTATION_NOT_ON_EXPECTED = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Errors/warnings inside code blocks
|
||||
|
||||
+3
@@ -284,6 +284,9 @@ public class DefaultErrorMessages {
|
||||
NAME, IncompatibleExpectedActualClassScopesRenderer.TEXT);
|
||||
MAP.put(ACTUAL_MISSING, "Declaration must be marked with 'actual'");
|
||||
|
||||
MAP.put(OPTIONAL_EXPECTATION_NOT_ON_EXPECTED, "'@OptionalExpectation' can only be used on an expected annotation class");
|
||||
MAP.put(OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY, "Declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry");
|
||||
|
||||
MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties");
|
||||
MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here");
|
||||
MAP.put(NOTHING_TO_OVERRIDE, "''{0}'' overrides nothing", NAME);
|
||||
|
||||
@@ -19,10 +19,7 @@ import org.jetbrains.kotlin.lexer.KtKeywordToken;
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker;
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext;
|
||||
import org.jetbrains.kotlin.resolve.checkers.PublishedApiUsageChecker;
|
||||
import org.jetbrains.kotlin.resolve.checkers.UnderscoreChecker;
|
||||
import org.jetbrains.kotlin.resolve.checkers.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -275,6 +272,7 @@ public class ModifiersChecker {
|
||||
}
|
||||
OperatorModifierChecker.INSTANCE.check(declaration, descriptor, trace, languageVersionSettings);
|
||||
PublishedApiUsageChecker.INSTANCE.check(declaration, descriptor, trace);
|
||||
OptionalExpectationTargetChecker.INSTANCE.check(declaration, descriptor, trace);
|
||||
}
|
||||
|
||||
public void checkTypeParametersModifiers(@NotNull KtModifierListOwner modifierListOwner) {
|
||||
|
||||
@@ -100,7 +100,8 @@ private val DEFAULT_CALL_CHECKERS = listOf(
|
||||
)
|
||||
private val DEFAULT_TYPE_CHECKERS = emptyList<AdditionalTypeChecker>()
|
||||
private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf(
|
||||
DeprecatedClassifierUsageChecker(), ApiVersionClassifierUsageChecker, MissingDependencyClassChecker.ClassifierUsage
|
||||
DeprecatedClassifierUsageChecker(), ApiVersionClassifierUsageChecker, MissingDependencyClassChecker.ClassifierUsage,
|
||||
OptionalExpectationUsageChecker()
|
||||
)
|
||||
private val DEFAULT_ANNOTATION_CHECKERS = listOf<AdditionalAnnotationChecker>(
|
||||
ExperimentalMarkerDeclarationAnnotationChecker
|
||||
|
||||
+9
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -41,6 +42,8 @@ import org.jetbrains.kotlin.utils.ifEmpty
|
||||
import java.io.File
|
||||
|
||||
object ExpectedActualDeclarationChecker : DeclarationChecker {
|
||||
internal val OPTIONAL_EXPECTATION_FQ_NAME = FqName("kotlin.OptionalExpectation")
|
||||
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)) return
|
||||
|
||||
@@ -67,6 +70,8 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
|
||||
|
||||
val compatibility = ExpectedActualResolver.findActualForExpected(descriptor, platformModule) ?: return
|
||||
|
||||
if (compatibility.allStrongIncompatibilities() && isOptionalAnnotationClass(descriptor)) return
|
||||
|
||||
val shouldReportError =
|
||||
compatibility.allStrongIncompatibilities() ||
|
||||
Compatible !in compatibility && compatibility.values.flatMapTo(hashSetOf()) { it }.all { actual ->
|
||||
@@ -89,6 +94,10 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun isOptionalAnnotationClass(descriptor: DeclarationDescriptor): Boolean {
|
||||
return descriptor.annotations.hasAnnotation(OPTIONAL_EXPECTATION_FQ_NAME)
|
||||
}
|
||||
|
||||
private fun ExpectActualTracker.reportExpectActual(expected: MemberDescriptor, actualMembers: Sequence<MemberDescriptor>) {
|
||||
if (this is ExpectActualTracker.DoNothing) return
|
||||
|
||||
|
||||
-12
@@ -265,18 +265,6 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiElement.isUsageAsAnnotationOrImport(): Boolean {
|
||||
val parent = parent
|
||||
|
||||
if (parent is KtUserType) {
|
||||
return parent.parent is KtTypeReference &&
|
||||
parent.parent.parent is KtConstructorCalleeExpression &&
|
||||
parent.parent.parent.parent is KtAnnotationEntry
|
||||
}
|
||||
|
||||
return parent is KtDotQualifiedExpression && parent.parent is KtImportDirective
|
||||
}
|
||||
|
||||
private fun PsiElement.isUsageAsQualifier(): Boolean {
|
||||
if (this is KtSimpleNameExpression) {
|
||||
val qualifier = getTopmostParentQualifiedExpressionForSelector() ?: this
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.checkers
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
|
||||
object OptionalExpectationTargetChecker {
|
||||
fun check(
|
||||
declaration: KtDeclaration,
|
||||
descriptor: DeclarationDescriptor,
|
||||
trace: BindingTrace
|
||||
) {
|
||||
if (descriptor is MemberDescriptor && descriptor.isExpect) return
|
||||
|
||||
for (entry in declaration.annotationEntries) {
|
||||
val annotationDescriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue
|
||||
if (annotationDescriptor.fqName == ExpectedActualDeclarationChecker.OPTIONAL_EXPECTATION_FQ_NAME) {
|
||||
trace.report(Errors.OPTIONAL_EXPECTATION_NOT_ON_EXPECTED.on(entry))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
|
||||
class OptionalExpectationUsageChecker : ClassifierUsageChecker {
|
||||
override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
|
||||
if (!ExpectedActualDeclarationChecker.isOptionalAnnotationClass(targetDescriptor)) return
|
||||
|
||||
if (!element.isUsageAsAnnotationOrImport()) {
|
||||
context.trace.report(Errors.OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY.on(element))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
internal fun PsiElement.isUsageAsAnnotationOrImport(): Boolean {
|
||||
val parent = parent
|
||||
|
||||
if (parent is KtUserType) {
|
||||
return parent.parent is KtTypeReference &&
|
||||
parent.parent.parent is KtConstructorCalleeExpression &&
|
||||
parent.parent.parent.parent is KtAnnotationEntry
|
||||
}
|
||||
|
||||
return parent is KtDotQualifiedExpression && parent.parent is KtImportDirective
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
@JvmName("bar")
|
||||
fun foo() {}
|
||||
|
||||
fun getJvmName(): JvmName? =
|
||||
Class.forName("LoadJvmNameKt").declaredMethods.single { it.name == "bar" }.getAnnotation(JvmName::class.java)
|
||||
|
||||
fun box(): String {
|
||||
// JvmName is binary-retained and should not be accessible via reflection
|
||||
return if (getJvmName() == null) "OK" else "Fail"
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalMultiplatform
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// FILE: common.kt
|
||||
|
||||
@OptionalExpectation
|
||||
expect annotation class Anno(val s: String)
|
||||
|
||||
// FILE: jvm.kt
|
||||
|
||||
import java.lang.reflect.AnnotatedElement
|
||||
|
||||
@Anno("Foo")
|
||||
class Foo @Anno("<init>") constructor(@Anno("x") x: Int) {
|
||||
@Anno("bar")
|
||||
fun bar() {}
|
||||
|
||||
@Anno("getX")
|
||||
var x = x
|
||||
@Anno("setX")
|
||||
set
|
||||
|
||||
@Anno("Nested")
|
||||
interface Nested
|
||||
}
|
||||
|
||||
private fun check(element: AnnotatedElement) {
|
||||
check(element.annotations)
|
||||
}
|
||||
|
||||
private fun check(annotations: Array<Annotation>) {
|
||||
val filtered = annotations.filterNot { it.annotationClass.java.name == "kotlin.Metadata" }
|
||||
if (filtered.isNotEmpty()) {
|
||||
throw AssertionError("Annotations should be empty: $filtered")
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val foo = Foo::class.java
|
||||
check(foo)
|
||||
check(Foo.Nested::class.java)
|
||||
check(foo.declaredMethods.single { it.name == "bar" })
|
||||
check(foo.declaredMethods.single { it.name == "getX" })
|
||||
check(foo.declaredMethods.single { it.name == "setX" })
|
||||
check(foo.constructors.single())
|
||||
check(foo.constructors.single().parameterAnnotations.single())
|
||||
return "OK"
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalMultiplatform
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
@OptionalExpectation
|
||||
expect annotation class Anno(val s: String)
|
||||
|
||||
@Anno("Foo")
|
||||
class Foo @Anno("<init>") constructor(@Anno("x") x: Int) {
|
||||
@Anno("bar")
|
||||
fun bar() {}
|
||||
|
||||
@Anno("getX")
|
||||
var x = x
|
||||
@Anno("setX")
|
||||
set
|
||||
|
||||
@Anno("Nested")
|
||||
interface Nested
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
@kotlin.Metadata
|
||||
public interface Foo$Nested {
|
||||
inner class Foo$Nested
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class Foo {
|
||||
private field x: int
|
||||
inner class Foo$Nested
|
||||
public method <init>(p0: int): void
|
||||
public final method bar(): void
|
||||
public final method getX(): int
|
||||
public final method setX(p0: int): void
|
||||
public synthetic deprecated static method x$annotations(): void
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// WITH_RUNTIME
|
||||
// ADDITIONAL_COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.ExperimentalMultiplatform
|
||||
|
||||
@OptionalExpectation
|
||||
expect annotation class A()
|
||||
|
||||
expect class C {
|
||||
@A
|
||||
fun f()
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
actual class C {
|
||||
actual fun f() {}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
actual annotation class A
|
||||
|
||||
actual class C {
|
||||
@A
|
||||
actual fun f() {}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
-- Common --
|
||||
Exit code: OK
|
||||
Output:
|
||||
|
||||
-- JVM --
|
||||
Exit code: OK
|
||||
Output:
|
||||
|
||||
-- JS --
|
||||
Exit code: OK
|
||||
Output:
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// WITH_RUNTIME
|
||||
// ADDITIONAL_COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.ExperimentalMultiplatform
|
||||
|
||||
@OptionalExpectation
|
||||
expect annotation class A()
|
||||
|
||||
fun useInSignature(a: A) = a.toString()
|
||||
|
||||
@OptionalExpectation
|
||||
expect class NotAnAnnotationClass
|
||||
|
||||
@OptionalExpectation
|
||||
annotation class NotAnExpectedClass
|
||||
|
||||
|
||||
|
||||
annotation class InOtherAnnotation(val a: A)
|
||||
|
||||
@InOtherAnnotation(A())
|
||||
fun useInOtherAnnotation() {}
|
||||
@@ -0,0 +1,6 @@
|
||||
fun useInReturnType(): A? = null
|
||||
|
||||
annotation class AnotherAnnotation(val a: A)
|
||||
|
||||
@AnotherAnnotation(A())
|
||||
fun useInAnotherAnnotation() {}
|
||||
@@ -0,0 +1,46 @@
|
||||
-- Common --
|
||||
Exit code: COMPILATION_ERROR
|
||||
Output:
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:7:23: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
|
||||
fun useInSignature(a: A) = a.toString()
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:9:1: error: this annotation is not applicable to target 'class'
|
||||
@OptionalExpectation
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:12:1: error: '@OptionalExpectation' can only be used on an expected annotation class
|
||||
@OptionalExpectation
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:17:43: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
|
||||
annotation class InOtherAnnotation(val a: A)
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:19:20: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
|
||||
@InOtherAnnotation(A())
|
||||
^
|
||||
|
||||
-- JVM --
|
||||
Exit code: COMPILATION_ERROR
|
||||
Output:
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:7:23: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
|
||||
fun useInSignature(a: A) = a.toString()
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:9:1: error: this annotation is not applicable to target 'class'
|
||||
@OptionalExpectation
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:12:1: error: '@OptionalExpectation' can only be used on an expected annotation class
|
||||
@OptionalExpectation
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:17:43: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
|
||||
annotation class InOtherAnnotation(val a: A)
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:19:20: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
|
||||
@InOtherAnnotation(A())
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:1:24: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
|
||||
fun useInReturnType(): A? = null
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:3:43: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
|
||||
annotation class AnotherAnnotation(val a: A)
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:5:20: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
|
||||
@AnotherAnnotation(A())
|
||||
^
|
||||
Generated
+10
@@ -12078,6 +12078,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/jvmName/functionName.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("loadJvmName.kt")
|
||||
public void testLoadJvmName() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmName/loadJvmName.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multifileClass.kt")
|
||||
public void testMultifileClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmName/multifileClass.kt");
|
||||
@@ -13440,6 +13445,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/multiplatform/noArgActualConstructor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("optionalExpectation.kt")
|
||||
public void testOptionalExpectation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/optionalExpectation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/multiplatform/defaultArguments")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+10
@@ -12078,6 +12078,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/jvmName/functionName.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("loadJvmName.kt")
|
||||
public void testLoadJvmName() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmName/loadJvmName.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multifileClass.kt")
|
||||
public void testMultifileClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmName/multifileClass.kt");
|
||||
@@ -13440,6 +13445,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/noArgActualConstructor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("optionalExpectation.kt")
|
||||
public void testOptionalExpectation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/optionalExpectation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/multiplatform/defaultArguments")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+18
@@ -286,6 +286,24 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeListing/multiplatform")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Multiplatform extends AbstractBytecodeListingTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInMultiplatform() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/multiplatform"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("optionalExpectation.kt")
|
||||
public void testOptionalExpectation() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/multiplatform/optionalExpectation.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeListing/specialBridges")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+10
@@ -12078,6 +12078,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/jvmName/functionName.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("loadJvmName.kt")
|
||||
public void testLoadJvmName() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmName/loadJvmName.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multifileClass.kt")
|
||||
public void testMultifileClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmName/multifileClass.kt");
|
||||
@@ -13440,6 +13445,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/multiplatform/noArgActualConstructor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("optionalExpectation.kt")
|
||||
public void testOptionalExpectation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/optionalExpectation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/multiplatform/defaultArguments")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Generated
+36
@@ -99,6 +99,16 @@ public class MultiPlatformIntegrationTestGenerated extends AbstractMultiPlatform
|
||||
runTest("compiler/testData/multiplatform/missingOverload/");
|
||||
}
|
||||
|
||||
@TestMetadata("optionalExpectation")
|
||||
public void testOptionalExpectation() throws Exception {
|
||||
runTest("compiler/testData/multiplatform/optionalExpectation/");
|
||||
}
|
||||
|
||||
@TestMetadata("optionalExpectationIncorrectUse")
|
||||
public void testOptionalExpectationIncorrectUse() throws Exception {
|
||||
runTest("compiler/testData/multiplatform/optionalExpectationIncorrectUse/");
|
||||
}
|
||||
|
||||
@TestMetadata("simple")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/multiplatform/simple/");
|
||||
@@ -569,6 +579,32 @@ public class MultiPlatformIntegrationTestGenerated extends AbstractMultiPlatform
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/multiplatform/optionalExpectation")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class OptionalExpectation extends AbstractMultiPlatformIntegrationTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInOptionalExpectation() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/multiplatform/optionalExpectation"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/multiplatform/optionalExpectationIncorrectUse")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class OptionalExpectationIncorrectUse extends AbstractMultiPlatformIntegrationTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInOptionalExpectationIncorrectUse() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/multiplatform/optionalExpectationIncorrectUse"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/multiplatform/regressions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -49,7 +49,8 @@ compileKotlinCommon {
|
||||
compileKotlinCommon {
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = [
|
||||
"-module-name", project.name
|
||||
"-module-name", project.name,
|
||||
"-Xuse-experimental=kotlin.Experimental"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -94,4 +95,4 @@ task distCommon(type: Copy) {
|
||||
|
||||
dist.dependsOn distCommon
|
||||
|
||||
classes.setDependsOn(classes.dependsOn.findAll { it != "compileJava" })
|
||||
classes.setDependsOn(classes.dependsOn.findAll { it != "compileJava" })
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.annotation.AnnotationTarget.*
|
||||
import kotlin.internal.RequireKotlin
|
||||
import kotlin.internal.RequireKotlinVersionKind
|
||||
|
||||
@Experimental
|
||||
@Target(
|
||||
CLASS,
|
||||
ANNOTATION_CLASS,
|
||||
PROPERTY,
|
||||
FIELD,
|
||||
LOCAL_VARIABLE,
|
||||
VALUE_PARAMETER,
|
||||
CONSTRUCTOR,
|
||||
FUNCTION,
|
||||
PROPERTY_GETTER,
|
||||
PROPERTY_SETTER,
|
||||
TYPEALIAS
|
||||
)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@RequireKotlin("1.2.50", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
|
||||
public annotation class ExperimentalMultiplatform
|
||||
|
||||
/**
|
||||
* This annotation is only applicable to `expect` annotation classes in multi-platform projects and marks that class as "optional".
|
||||
* Optional expected class is allowed to have no corresponding actual class on the platform. Optional annotations can only be used
|
||||
* to annotate something, not as types in signatures. If an optional annotation has no corresponding actual class on a platform,
|
||||
* the annotation entries where it's used are simply erased when compiling code on that platform.
|
||||
*/
|
||||
@Target(ANNOTATION_CLASS)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@ExperimentalMultiplatform
|
||||
@RequireKotlin("1.2.50", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
|
||||
public annotation class OptionalExpectation
|
||||
@@ -137,7 +137,10 @@ compileKotlin2Js {
|
||||
outputFile = "${buildDir}/classes/main/kotlin.js"
|
||||
sourceMap = true
|
||||
sourceMapPrefix = "./"
|
||||
freeCompilerArgs += ["-source-map-base-dirs", [builtinsSrcDir, jsSrcDir, commonSrcDir, commonSrcDir2].collect { file(it).absoluteFile }.join(File.pathSeparator)]
|
||||
freeCompilerArgs += [
|
||||
"-source-map-base-dirs", [builtinsSrcDir, jsSrcDir, commonSrcDir, commonSrcDir2].collect { file(it).absoluteFile }.join(File.pathSeparator),
|
||||
"-Xuse-experimental=kotlin.Experimental"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -174,7 +174,8 @@ compileKotlin {
|
||||
"-Xallow-kotlin-package",
|
||||
"-Xmultifile-parts-inherit",
|
||||
"-Xnormalize-constructor-calls=enable",
|
||||
"-module-name", "kotlin-stdlib"
|
||||
"-module-name", "kotlin-stdlib",
|
||||
"-Xuse-experimental=kotlin.Experimental"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -31,6 +31,9 @@ public final class kotlin/Experimental$Level : java/lang/Enum {
|
||||
public static fun values ()[Lkotlin/Experimental$Level;
|
||||
}
|
||||
|
||||
public abstract interface annotation class kotlin/ExperimentalMultiplatform : java/lang/annotation/Annotation {
|
||||
}
|
||||
|
||||
public abstract interface annotation class kotlin/ExtensionFunctionType : java/lang/annotation/Annotation {
|
||||
}
|
||||
|
||||
@@ -96,6 +99,9 @@ public final class kotlin/NotImplementedError : java/lang/Error {
|
||||
public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
}
|
||||
|
||||
public abstract interface annotation class kotlin/OptionalExpectation : java/lang/annotation/Annotation {
|
||||
}
|
||||
|
||||
public final class kotlin/Pair : java/io/Serializable {
|
||||
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
|
||||
public final fun component1 ()Ljava/lang/Object;
|
||||
|
||||
Reference in New Issue
Block a user