From 167ab1f860fc8a3541feb3d3b1c895ef26b5abae Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 26 Sep 2016 19:56:22 +0300 Subject: [PATCH] Introduce "-api-version" CLI option The `@SinceKotlin("X.Y.Z")` annotation now hides a particular declaration from resolution when the API version specified by the `-api-version` option is _less_ than X.Y.Z. The comparison is performed as for versions in Maven: MavenComparableVersion is in fact a copy of org.apache.maven.artifact.versioning.ComparableVersion. Also support "!API_VERSION" directive in diagnostic tests #KT-14298 Fixed --- .../arguments/CommonCompilerArguments.java | 5 + .../kotlin/cli/common/CLICompiler.java | 59 +- .../jetbrains/kotlin/diagnostics/Errors.java | 8 +- .../rendering/DefaultErrorMessages.java | 2 + .../kotlin/resolve/TargetPlatform.kt | 4 +- .../calls/checkers/ApiVersionCallChecker.kt | 47 ++ .../calls/checkers/DeprecatedCallChecker.kt | 2 +- .../ApiVersionClassifierUsageChecker.kt | 37 ++ .../kotlin/resolve/deprecationUtil.kt | 3 + .../kotlin/resolve/sinceKotlinUtil.kt | 48 ++ compiler/testData/cli/js/jsHelp.out | 1 + compiler/testData/cli/jvm/apiVersion.args | 5 + compiler/testData/cli/jvm/apiVersion.kt | 3 + compiler/testData/cli/jvm/apiVersion.out | 4 + .../jvm/apiVersionGreaterThanLanguage.args | 7 + .../cli/jvm/apiVersionGreaterThanLanguage.out | 2 + .../testData/cli/jvm/apiVersionInvalid.args | 5 + .../testData/cli/jvm/apiVersionInvalid.out | 3 + .../cli/jvm/apiVersionLessThanLanguage.args | 7 + .../cli/jvm/apiVersionLessThanLanguage.out | 4 + compiler/testData/cli/jvm/help.out | 1 + compiler/testData/cli/jvm/languageVersion.kt | 4 + compiler/testData/cli/jvm/languageVersion.out | 6 + compiler/testData/cli/jvm/wrongArgument.out | 1 + compiler/testData/diagnostics/ReadMe.md | 8 + .../duplicateMethod/sinceKotlin.kt | 34 ++ .../duplicateMethod/sinceKotlin.txt | 29 + .../hiddenClass/sinceKotlinImportPriority.kt | 38 ++ .../hiddenClass/sinceKotlinImportPriority.txt | 49 ++ .../hiddenClass/sinceKotlinMultipleClasses.kt | 47 ++ .../sinceKotlinMultipleClasses.txt | 71 +++ .../apiVersion/annotations.kt | 11 + .../apiVersion/annotations.txt | 18 + .../apiVersion/classesAndConstructors.kt | 19 + .../apiVersion/classesAndConstructors.txt | 27 + .../apiVersion/overriddenMembers.kt | 34 ++ .../apiVersion/overriddenMembers.txt | 59 ++ .../apiVersion/propertyAccessors.kt | 48 ++ .../apiVersion/propertyAccessors.txt | 10 + .../apiVersion/simpleMembers.kt | 19 + .../apiVersion/simpleMembers.txt | 9 + .../apiVersion/sinceOldVersionIsOK.kt | 18 + .../apiVersion/sinceOldVersionIsOK.txt | 10 + .../checkers/AbstractDiagnosticsTest.java | 14 +- .../kotlin/checkers/BaseDiagnosticsTest.java | 69 ++- .../checkers/DiagnosticsTestGenerated.java | 63 +++ .../kotlin/cli/CliTestGenerated.java | 24 + .../kotlin/code/CodeConformanceTest.kt | 5 +- .../org/jetbrains/kotlin/config/ApiVersion.kt | 48 ++ .../kotlin/config/LanguageVersionSettings.kt | 15 +- .../kotlin/config/MavenComparableVersion.java | 504 ++++++++++++++++++ core/builtins/src/kotlin/reflect/KClass.kt | 1 + .../AbstractDiagnosticMessageJsTest.java | 8 +- .../AbstractDiagnosticMessageTest.java | 8 +- .../kotlin/gradle/dsl/KotlinJsOptions.kt | 7 + .../kotlin/gradle/dsl/KotlinJsOptionsBase.kt | 7 + .../kotlin/gradle/dsl/KotlinJvmOptions.kt | 7 + .../kotlin/gradle/dsl/KotlinJvmOptionsBase.kt | 7 + license/third_party/maven_LICENSE.txt | 202 +++++++ 59 files changed, 1758 insertions(+), 57 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ApiVersionCallChecker.kt create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ApiVersionClassifierUsageChecker.kt create mode 100644 compiler/testData/cli/jvm/apiVersion.args create mode 100644 compiler/testData/cli/jvm/apiVersion.kt create mode 100644 compiler/testData/cli/jvm/apiVersion.out create mode 100644 compiler/testData/cli/jvm/apiVersionGreaterThanLanguage.args create mode 100644 compiler/testData/cli/jvm/apiVersionGreaterThanLanguage.out create mode 100644 compiler/testData/cli/jvm/apiVersionInvalid.args create mode 100644 compiler/testData/cli/jvm/apiVersionInvalid.out create mode 100644 compiler/testData/cli/jvm/apiVersionLessThanLanguage.args create mode 100644 compiler/testData/cli/jvm/apiVersionLessThanLanguage.out create mode 100644 compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sinceKotlin.kt create mode 100644 compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sinceKotlin.txt create mode 100644 compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinImportPriority.kt create mode 100644 compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinImportPriority.txt create mode 100644 compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinMultipleClasses.kt create mode 100644 compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinMultipleClasses.txt create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/annotations.kt create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/annotations.txt create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/classesAndConstructors.kt create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/classesAndConstructors.txt create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/overriddenMembers.kt create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/overriddenMembers.txt create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/propertyAccessors.kt create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/propertyAccessors.txt create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/simpleMembers.kt create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/simpleMembers.txt create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/sinceOldVersionIsOK.kt create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/sinceOldVersionIsOK.txt create mode 100644 compiler/util/src/org/jetbrains/kotlin/config/ApiVersion.kt create mode 100644 compiler/util/src/org/jetbrains/kotlin/config/MavenComparableVersion.java create mode 100644 license/third_party/maven_LICENSE.txt diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.java index 906a7412cbe..ce6bf7889a5 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.java +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.java @@ -30,6 +30,11 @@ public abstract class CommonCompilerArguments { @ValueDescription("") public String languageVersion; + @GradleOption(DefaultValues.LanguageVersions.class) + @Argument(value = "api-version", description = "Allow to use declarations only from the specified version of bundled libraries") + @ValueDescription("") + public String apiVersion; + @GradleOption(DefaultValues.BooleanFalseDefault.class) @Argument(value = "nowarn", description = "Generate no warnings") public boolean suppressWarnings; diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java index 7e0b3541245..0b6f5b24803 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java @@ -248,27 +248,58 @@ public abstract class CLICompiler { configuration.put(CLIConfigurationKeys.COMPILER_JAR_LOCATOR, locator); } - if (arguments.languageVersion != null) { - LanguageVersion languageVersion = LanguageVersion.fromVersionString(arguments.languageVersion); - if (languageVersion != null) { - configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, new LanguageVersionSettingsImpl(languageVersion)); + LanguageVersion languageVersion = parseVersion(configuration, arguments.languageVersion, "language"); + LanguageVersion apiVersion = parseVersion(configuration, arguments.apiVersion, "API"); + if (languageVersion != null || apiVersion != null) { + if (languageVersion == null) { + // If only "-api-version" is specified, language version is assumed to be the latest + languageVersion = LanguageVersion.LATEST; } - else { - List versionStrings = ArraysKt.map(LanguageVersion.values(), new Function1() { - @Override - public String invoke(LanguageVersion version) { - return version.getVersionString(); - } - }); - String message = "Unknown language version: " + arguments.languageVersion + "\n" + - "Supported language versions: " + StringsKt.join(versionStrings, ", "); + if (apiVersion == null) { + // If only "-language-version" is specified, API version is assumed to be equal to the language version + // (API version cannot be greater than the language version) + apiVersion = languageVersion; + } + + if (apiVersion.compareTo(languageVersion) > 0) { configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report( - CompilerMessageSeverity.ERROR, message, CompilerMessageLocation.NO_LOCATION + CompilerMessageSeverity.ERROR, + "-api-version (" + apiVersion.getVersionString() + ") cannot be greater than " + + "-language-version (" + languageVersion.getVersionString() + ")", + CompilerMessageLocation.NO_LOCATION ); } + + configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, + new LanguageVersionSettingsImpl(languageVersion, ApiVersion.createByLanguageVersion(apiVersion))); } } + private static LanguageVersion parseVersion( + @NotNull CompilerConfiguration configuration, @Nullable String value, @NotNull String versionOf + ) { + if (value == null) return null; + + LanguageVersion version = LanguageVersion.fromVersionString(value); + if (version != null) { + return version; + } + + List versionStrings = ArraysKt.map(LanguageVersion.values(), new Function1() { + @Override + public String invoke(LanguageVersion version) { + return version.getVersionString(); + } + }); + String message = "Unknown " + versionOf + " version: " + value + "\n" + + "Supported " + versionOf + " versions: " + StringsKt.join(versionStrings, ", "); + configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report( + CompilerMessageSeverity.ERROR, message, CompilerMessageLocation.NO_LOCATION + ); + + return null; + } + protected abstract void setupPlatformSpecificArgumentsAndServices( @NotNull CompilerConfiguration configuration, @NotNull A arguments, @NotNull Services services ); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 06b990407ab..73646f21242 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -73,6 +73,11 @@ public interface Errors { DiagnosticFactory1 UNRESOLVED_REFERENCE = DiagnosticFactory1.create(ERROR, FOR_UNRESOLVED_REFERENCE); + DiagnosticFactory2 DEPRECATION = DiagnosticFactory2.create(WARNING); + DiagnosticFactory2 DEPRECATION_ERROR = DiagnosticFactory2.create(ERROR); + + DiagnosticFactory2 API_NOT_AVAILABLE = DiagnosticFactory2.create(ERROR); + //Elements with "INVISIBLE_REFERENCE" error are marked as unresolved, unlike elements with "INVISIBLE_MEMBER" error //"INVISIBLE_REFERENCE" is used for invisible classes references and references in import DiagnosticFactory3 INVISIBLE_REFERENCE = @@ -278,9 +283,6 @@ public interface Errors { DiagnosticFactory0 MANY_COMPANION_OBJECTS = DiagnosticFactory0.create(ERROR, COMPANION_OBJECT); - DiagnosticFactory2 DEPRECATION = DiagnosticFactory2.create(WARNING); - DiagnosticFactory2 DEPRECATION_ERROR = DiagnosticFactory2.create(ERROR); - // Objects DiagnosticFactory1 LOCAL_OBJECT_NOT_ALLOWED = DiagnosticFactory1.create(ERROR, DECLARATION_NAME); 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 8a7e24a5edf..b7ff3119e07 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -300,6 +300,8 @@ public class DefaultErrorMessages { MAP.put(DEPRECATION, "''{0}'' is deprecated. {1}", DEPRECATION_RENDERER, STRING); MAP.put(DEPRECATION_ERROR, "Using ''{0}'' is an error. {1}", DEPRECATION_RENDERER, STRING); + MAP.put(API_NOT_AVAILABLE, "This declaration is only available since Kotlin {0} and cannot be used with the specified API version {1}", STRING, STRING); + MAP.put(LOCAL_OBJECT_NOT_ALLOWED, "Named object ''{0}'' is a singleton and cannot be local. Try to use anonymous object instead", NAME); MAP.put(LOCAL_INTERFACE_NOT_ALLOWED, "''{0}'' is an interface so it cannot be local. Try to use anonymous object or abstract class instead", NAME); MAP.put(ENUM_CLASS_CONSTRUCTOR_CALL, "Enum types cannot be instantiated"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index e45eea384b1..b892437ac48 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -71,11 +71,11 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf( private val DEFAULT_CALL_CHECKERS = listOf( CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker(), SafeCallChecker(), DeprecatedCallChecker, CallReturnsArrayOfNothingChecker(), InfixCallChecker(), OperatorCallChecker(), - ConstructorHeaderCallChecker, ProtectedConstructorCallChecker, + ConstructorHeaderCallChecker, ProtectedConstructorCallChecker, ApiVersionCallChecker, CoroutineSuspendCallChecker, BuilderFunctionsCallChecker ) private val DEFAULT_TYPE_CHECKERS = emptyList() -private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf(DeprecatedClassifierUsageChecker()) +private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf(DeprecatedClassifierUsageChecker(), ApiVersionClassifierUsageChecker) abstract class PlatformConfigurator( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ApiVersionCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ApiVersionCallChecker.kt new file mode 100644 index 00000000000..20d9000c340 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ApiVersionCallChecker.kt @@ -0,0 +1,47 @@ +/* + * 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.calls.checkers + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.diagnostics.Errors.API_NOT_AVAILABLE +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject +import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility + +// TODO: consider combining with DeprecatedCallChecker somehow +object ApiVersionCallChecker : CallChecker { + override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { + check(resolvedCall.resultingDescriptor, context, reportOn) + } + + private fun check(targetDescriptor: CallableDescriptor, context: CallCheckerContext, element: PsiElement) { + // Objects will be checked by ApiVersionClassifierUsageChecker + if (targetDescriptor is FakeCallableDescriptorForObject) return + + val accessible = targetDescriptor.checkSinceKotlinVersionAccessibility(context.languageVersionSettings) { version -> + context.trace.report( + API_NOT_AVAILABLE.on(element, version.versionString, context.languageVersionSettings.apiVersion.versionString) + ) + } + + if (accessible && targetDescriptor is PropertyDescriptor && DeprecatedCallChecker.shouldCheckPropertyGetter(element)) { + targetDescriptor.getter?.let { check(it, context, element) } + } + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/DeprecatedCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/DeprecatedCallChecker.kt index 862cb7ec569..2be15fe9c5f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/DeprecatedCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/DeprecatedCallChecker.kt @@ -57,7 +57,7 @@ object DeprecatedCallChecker : CallChecker { private val PROPERTY_SET_OPERATIONS = TokenSet.create(*KtTokens.ALL_ASSIGNMENTS.types, KtTokens.PLUSPLUS, KtTokens.MINUSMINUS) - private fun shouldCheckPropertyGetter(expression: PsiElement): Boolean { + internal fun shouldCheckPropertyGetter(expression: PsiElement): Boolean { // property getters do not come as callable yet, so we analyse surroundings to check for deprecation annotation on getter val binaryExpression = PsiTreeUtil.getParentOfType(expression, KtBinaryExpression::class.java) if (binaryExpression != null) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ApiVersionClassifierUsageChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ApiVersionClassifierUsageChecker.kt new file mode 100644 index 00000000000..3e03593ac65 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ApiVersionClassifierUsageChecker.kt @@ -0,0 +1,37 @@ +/* + * 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.checkers + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.descriptors.ClassifierDescriptor +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility + +object ApiVersionClassifierUsageChecker : ClassifierUsageChecker { + override fun check( + targetDescriptor: ClassifierDescriptor, + trace: BindingTrace, + element: PsiElement, + languageVersionSettings: LanguageVersionSettings + ) { + targetDescriptor.checkSinceKotlinVersionAccessibility(languageVersionSettings) { version -> + trace.report(Errors.API_NOT_AVAILABLE.on(element, version.versionString, languageVersionSettings.apiVersion.versionString)) + } + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt index d9b8d265d53..352aac4fe52 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt @@ -196,5 +196,8 @@ fun DeclarationDescriptor.isHiddenInResolution(languageVersionSettings: Language if (isHiddenToOvercomeSignatureClash) return true if (isHiddenForResolutionEverywhereBesideSupercalls && !isSuperCall) return true } + + if (!checkSinceKotlinVersionAccessibility(languageVersionSettings)) return true + return isDeprecatedHidden() } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt index 9254c5c1700..36ad1c1be0e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt @@ -16,11 +16,59 @@ package org.jetbrains.kotlin.resolve +import org.jetbrains.kotlin.config.ApiVersion +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.name.FqName private val SINCE_KOTLIN_FQ_NAME = FqName("kotlin.SinceKotlin") +// TODO: use-site targeted annotations internal fun DeclarationDescriptor.getSinceKotlinAnnotation(): AnnotationDescriptor? = annotations.findAnnotation(SINCE_KOTLIN_FQ_NAME) + +/** + * @return true if the descriptor is accessible according to [languageVersionSettings], or false otherwise. The [actionIfInaccessible] + * callback is called with the version specified in the [SinceKotlin] annotation if the descriptor is inaccessible. + */ +internal fun DeclarationDescriptor.checkSinceKotlinVersionAccessibility( + languageVersionSettings: LanguageVersionSettings, + actionIfInaccessible: ((ApiVersion) -> Unit)? = null +): Boolean { + val version = + if (this is CallableMemberDescriptor && !kind.isReal) getSinceKotlinVersionByOverridden(this) + else getOwnSinceKotlinVersion() + + // Allow access in the following cases: + // 1) There's no @SinceKotlin annotation for this descriptor + // 2) There's a @SinceKotlin annotation but its value is some unrecognizable nonsense + // 3) The value as a version is not greater than our API version + if (version == null || version <= languageVersionSettings.apiVersion) return true + + actionIfInaccessible?.invoke(version) + + return false +} + +/** + * @return null if there are no overridden members or if there's at least one declaration in the hierarchy not annotated with [SinceKotlin], + * or the minimal value of the version from all declarations annotated with [SinceKotlin] otherwise. + */ +private fun getSinceKotlinVersionByOverridden(descriptor: CallableMemberDescriptor): ApiVersion? { + return DescriptorUtils.getAllOverriddenDeclarations(descriptor).map { it.getOwnSinceKotlinVersion() ?: return null }.min() +} + +private fun DeclarationDescriptor.getOwnSinceKotlinVersion(): ApiVersion? { + fun DeclarationDescriptor.loadAnnotationValue(): ApiVersion? = + (getSinceKotlinAnnotation()?.allValueArguments?.values?.singleOrNull()?.value as? String)?.let(ApiVersion.Companion::parse) + + val ownVersion = loadAnnotationValue() + val ctorClass = (this as? ConstructorDescriptor)?.containingDeclaration?.loadAnnotationValue() + val property = (this as? PropertyAccessorDescriptor)?.correspondingProperty?.loadAnnotationValue() + + return listOfNotNull(ownVersion, ctorClass, property).max() +} diff --git a/compiler/testData/cli/js/jsHelp.out b/compiler/testData/cli/js/jsHelp.out index 101a52bfe90..0b08b09ad61 100644 --- a/compiler/testData/cli/js/jsHelp.out +++ b/compiler/testData/cli/js/jsHelp.out @@ -13,6 +13,7 @@ where possible options include: -output-prefix Path to file which will be added to the beginning of output file -output-postfix Path to file which will be added to the end of output file -language-version Provide source compatibility with specified language version + -api-version Allow to use declarations only from the specified version of bundled libraries -nowarn Generate no warnings -verbose Enable verbose logging output -version Display compiler version diff --git a/compiler/testData/cli/jvm/apiVersion.args b/compiler/testData/cli/jvm/apiVersion.args new file mode 100644 index 00000000000..e6a17467052 --- /dev/null +++ b/compiler/testData/cli/jvm/apiVersion.args @@ -0,0 +1,5 @@ +$TESTDATA_DIR$/apiVersion.kt +-d +$TEMP_DIR$ +-api-version +1.0 diff --git a/compiler/testData/cli/jvm/apiVersion.kt b/compiler/testData/cli/jvm/apiVersion.kt new file mode 100644 index 00000000000..8d4661d72c0 --- /dev/null +++ b/compiler/testData/cli/jvm/apiVersion.kt @@ -0,0 +1,3 @@ +fun test() { + ""::class.isInstance(42) +} diff --git a/compiler/testData/cli/jvm/apiVersion.out b/compiler/testData/cli/jvm/apiVersion.out new file mode 100644 index 00000000000..33e62bb3fde --- /dev/null +++ b/compiler/testData/cli/jvm/apiVersion.out @@ -0,0 +1,4 @@ +compiler/testData/cli/jvm/apiVersion.kt:2:15: error: unresolved reference: isInstance + ""::class.isInstance(42) + ^ +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/apiVersionGreaterThanLanguage.args b/compiler/testData/cli/jvm/apiVersionGreaterThanLanguage.args new file mode 100644 index 00000000000..70d1ba13868 --- /dev/null +++ b/compiler/testData/cli/jvm/apiVersionGreaterThanLanguage.args @@ -0,0 +1,7 @@ +$TESTDATA_DIR$/apiVersion.kt +-d +$TEMP_DIR$ +-api-version +1.1 +-language-version +1.0 diff --git a/compiler/testData/cli/jvm/apiVersionGreaterThanLanguage.out b/compiler/testData/cli/jvm/apiVersionGreaterThanLanguage.out new file mode 100644 index 00000000000..47a8f88e3a8 --- /dev/null +++ b/compiler/testData/cli/jvm/apiVersionGreaterThanLanguage.out @@ -0,0 +1,2 @@ +error: -api-version (1.1) cannot be greater than -language-version (1.0) +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/apiVersionInvalid.args b/compiler/testData/cli/jvm/apiVersionInvalid.args new file mode 100644 index 00000000000..5139d064397 --- /dev/null +++ b/compiler/testData/cli/jvm/apiVersionInvalid.args @@ -0,0 +1,5 @@ +$TESTDATA_DIR$/simple.kt +-d +$TEMP_DIR$ +-api-version +239.42 diff --git a/compiler/testData/cli/jvm/apiVersionInvalid.out b/compiler/testData/cli/jvm/apiVersionInvalid.out new file mode 100644 index 00000000000..e0ff180c445 --- /dev/null +++ b/compiler/testData/cli/jvm/apiVersionInvalid.out @@ -0,0 +1,3 @@ +error: unknown API version: 239.42 +Supported API versions: 1.0, 1.1 +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/apiVersionLessThanLanguage.args b/compiler/testData/cli/jvm/apiVersionLessThanLanguage.args new file mode 100644 index 00000000000..6ac842f7e60 --- /dev/null +++ b/compiler/testData/cli/jvm/apiVersionLessThanLanguage.args @@ -0,0 +1,7 @@ +$TESTDATA_DIR$/apiVersion.kt +-d +$TEMP_DIR$ +-api-version +1.0 +-language-version +1.1 diff --git a/compiler/testData/cli/jvm/apiVersionLessThanLanguage.out b/compiler/testData/cli/jvm/apiVersionLessThanLanguage.out new file mode 100644 index 00000000000..33e62bb3fde --- /dev/null +++ b/compiler/testData/cli/jvm/apiVersionLessThanLanguage.out @@ -0,0 +1,4 @@ +compiler/testData/cli/jvm/apiVersion.kt:2:15: error: unresolved reference: isInstance + ""::class.isInstance(42) + ^ +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/help.out b/compiler/testData/cli/jvm/help.out index d5dcc9e50de..66e5cd9ff39 100644 --- a/compiler/testData/cli/jvm/help.out +++ b/compiler/testData/cli/jvm/help.out @@ -15,6 +15,7 @@ where possible options include: -module-name Module name -jvm-target Target version of the generated JVM bytecode (1.6 or 1.8), default is 1.6 -language-version Provide source compatibility with specified language version + -api-version Allow to use declarations only from the specified version of bundled libraries -nowarn Generate no warnings -verbose Enable verbose logging output -version Display compiler version diff --git a/compiler/testData/cli/jvm/languageVersion.kt b/compiler/testData/cli/jvm/languageVersion.kt index 73d94ad88be..1eb94bd3466 100644 --- a/compiler/testData/cli/jvm/languageVersion.kt +++ b/compiler/testData/cli/jvm/languageVersion.kt @@ -3,3 +3,7 @@ package test sealed class Base class Derived : Base() + +fun test() { + ""::class.isInstance(42) +} diff --git a/compiler/testData/cli/jvm/languageVersion.out b/compiler/testData/cli/jvm/languageVersion.out index cdd464da409..4bd2f466360 100644 --- a/compiler/testData/cli/jvm/languageVersion.out +++ b/compiler/testData/cli/jvm/languageVersion.out @@ -1,4 +1,10 @@ compiler/testData/cli/jvm/languageVersion.kt:5:17: error: this type is sealed, so it can be inherited by only its own nested classes or objects class Derived : Base() ^ +compiler/testData/cli/jvm/languageVersion.kt:8:5: error: the feature is only available since Kotlin 1.1: bound callable references + ""::class.isInstance(42) + ^ +compiler/testData/cli/jvm/languageVersion.kt:8:15: error: unresolved reference: isInstance + ""::class.isInstance(42) + ^ COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/wrongArgument.out b/compiler/testData/cli/jvm/wrongArgument.out index 6d4131ddd1b..35d77484a70 100644 --- a/compiler/testData/cli/jvm/wrongArgument.out +++ b/compiler/testData/cli/jvm/wrongArgument.out @@ -16,6 +16,7 @@ where possible options include: -module-name Module name -jvm-target Target version of the generated JVM bytecode (1.6 or 1.8), default is 1.6 -language-version Provide source compatibility with specified language version + -api-version Allow to use declarations only from the specified version of bundled libraries -nowarn Generate no warnings -verbose Enable verbose logging output -version Display compiler version diff --git a/compiler/testData/diagnostics/ReadMe.md b/compiler/testData/diagnostics/ReadMe.md index cec9ce67785..121e0a17765 100644 --- a/compiler/testData/diagnostics/ReadMe.md +++ b/compiler/testData/diagnostics/ReadMe.md @@ -83,3 +83,11 @@ This directive lets you enable or disable certain language features. Language fe // !LANGUAGE: -TopLevelSealedInheritance // !LANGUAGE: +TypeAliases -LocalDelegatedProperties + +### 5. API_VERSION + +This directive emulates the behavior of the `-api-version` command line option, disallowing to use declarations annotated with `@SinceKotlin(X)` where X is greater than the specified API version. + +#### Usage: + + // !API_VERSION: 1.0 diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sinceKotlin.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sinceKotlin.kt new file mode 100644 index 00000000000..87c398e27f8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sinceKotlin.kt @@ -0,0 +1,34 @@ +// !API_VERSION: 1.0 +// MODULE: m1 +// FILE: a.kt + +package p1 + +@SinceKotlin("1.1") +fun foo(s: Int): String = s.toString() + +// MODULE: m2 +// FILE: b.kt + +package p2 + +fun foo(s: Int): Int = s + +// MODULE: m3(m1, m2) +// FILE: severalStarImports.kt +import p1.* +import p2.* + +fun test1(): Int { + val r = foo(42) + return r +} + +// FILE: explicitlyImportP1.kt +import p1.foo // TODO: consider reporting API_NOT_AVAILABLE here +import p2.* + +fun test2(): Int { + val r = foo(42) + return r +} diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sinceKotlin.txt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sinceKotlin.txt new file mode 100644 index 00000000000..702076ed83b --- /dev/null +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sinceKotlin.txt @@ -0,0 +1,29 @@ +// -- Module: -- +package + +package p1 { + @kotlin.SinceKotlin(version = "1.1") public fun foo(/*0*/ s: kotlin.Int): kotlin.String +} + + +// -- Module: -- +package + +package p2 { + public fun foo(/*0*/ s: kotlin.Int): kotlin.Int +} + + +// -- Module: -- +package + +public fun test1(): kotlin.Int +public fun test2(): kotlin.Int + +package p1 { + @kotlin.SinceKotlin(version = "1.1") public fun foo(/*0*/ s: kotlin.Int): kotlin.String +} + +package p2 { + public fun foo(/*0*/ s: kotlin.Int): kotlin.Int +} diff --git a/compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinImportPriority.kt b/compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinImportPriority.kt new file mode 100644 index 00000000000..f1e897f2cc2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinImportPriority.kt @@ -0,0 +1,38 @@ +// !API_VERSION: 1.0 +// MODULE: m1 +// FILE: a.kt + +package p1 + +@SinceKotlin("1.1") +class A { + fun m1() {} +} + +// MODULE: m2 +// FILE: b.kt + +package p2 + +class A { + fun m2() {} +} + +// MODULE: m3(m1, m2) +// FILE: severalStarImports.kt +import p1.* +import p2.* + +fun test(a: A) { + a.m1() + a.m2() +} + +// FILE: explicitlyImportP1.kt +import p1.A +import p2.* + +fun test(a: A) { + a.m1() + a.m2() +} diff --git a/compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinImportPriority.txt b/compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinImportPriority.txt new file mode 100644 index 00000000000..eaf4e477f92 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinImportPriority.txt @@ -0,0 +1,49 @@ +// -- Module: -- +package + +package p1 { + + @kotlin.SinceKotlin(version = "1.1") public final class A { + public constructor A() + 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 final fun m1(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + + +// -- Module: -- +package + +package p2 { + + public final class A { + public constructor A() + 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 final fun m2(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + + +// -- Module: -- +package + +public fun test(/*0*/ a: p1.A): kotlin.Unit +public fun test(/*0*/ a: p2.A): kotlin.Unit + +package p1 { + + @kotlin.SinceKotlin(version = "1.1") public final class A { + // -- Module: -- + } +} + +package p2 { + + public final class A { + // -- Module: -- + } +} diff --git a/compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinMultipleClasses.kt b/compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinMultipleClasses.kt new file mode 100644 index 00000000000..ea81d365db7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinMultipleClasses.kt @@ -0,0 +1,47 @@ +// !API_VERSION: 1.0 +// MODULE: m1 +// FILE: a.kt + +package p1 + +@SinceKotlin("1.1") +class A(val v1: Unit) + +// MODULE: m2 +// FILE: b.kt + +package p2 + +@SinceKotlin("1.1") +class A(val v2: Unit) + +// MODULE: m3 +// FILE: c.kt + +package p3 + +@SinceKotlin("1.1") +class A(val v3: Unit) + +// MODULE: m4(m1, m2, m3) +// FILE: oneExplicitImportOtherStars.kt +import p1.* +import p2.A +import p3.* + +fun test(a: A) { + a.v1 + a.v2 + a.v3 +} + +// FILE: severalStarImports.kt +import p1.* +import p2.* +import p3.* + +fun test(a: A) { + a.v1 + a.v2 + a.v3 +} diff --git a/compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinMultipleClasses.txt b/compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinMultipleClasses.txt new file mode 100644 index 00000000000..b6e4eba395a --- /dev/null +++ b/compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinMultipleClasses.txt @@ -0,0 +1,71 @@ +// -- Module: -- +package + +package p1 { + + @kotlin.SinceKotlin(version = "1.1") public final class A { + public constructor A(/*0*/ v1: kotlin.Unit) + public final val v1: 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 + } +} + + +// -- Module: -- +package + +package p2 { + + @kotlin.SinceKotlin(version = "1.1") public final class A { + public constructor A(/*0*/ v2: kotlin.Unit) + public final val v2: 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 + } +} + + +// -- Module: -- +package + +package p3 { + + @kotlin.SinceKotlin(version = "1.1") public final class A { + public constructor A(/*0*/ v3: kotlin.Unit) + public final val v3: 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 + } +} + + +// -- Module: -- +package + +public fun test(/*0*/ a: [ERROR : A]): kotlin.Unit +public fun test(/*0*/ a: p2.A): kotlin.Unit + +package p1 { + + @kotlin.SinceKotlin(version = "1.1") public final class A { + // -- Module: -- + } +} + +package p2 { + + @kotlin.SinceKotlin(version = "1.1") public final class A { + // -- Module: -- + } +} + +package p3 { + + @kotlin.SinceKotlin(version = "1.1") public final class A { + // -- Module: -- + } +} diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/annotations.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/annotations.kt new file mode 100644 index 00000000000..42042412e0f --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/annotations.kt @@ -0,0 +1,11 @@ +// !API_VERSION: 1.0 + +@SinceKotlin("1.1") +annotation class Anno1(val s: String) + +annotation class Anno2 @SinceKotlin("1.1") constructor() + + +@Anno1("") +@Anno2 +fun t1() {} diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/annotations.txt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/annotations.txt new file mode 100644 index 00000000000..f3a28488d38 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/annotations.txt @@ -0,0 +1,18 @@ +package + +@Anno1() @Anno2() public fun t1(): kotlin.Unit + +@kotlin.SinceKotlin(version = "1.1") public final annotation class Anno1 : kotlin.Annotation { + public constructor Anno1(/*0*/ s: kotlin.String) + public final val s: kotlin.String + 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 annotation class Anno2 : kotlin.Annotation { + @kotlin.SinceKotlin(version = "1.1") public constructor Anno2() + 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/sourceCompatibility/apiVersion/classesAndConstructors.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/classesAndConstructors.kt new file mode 100644 index 00000000000..aa0e96dc4f5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/classesAndConstructors.kt @@ -0,0 +1,19 @@ +// !API_VERSION: 1.0 + +@SinceKotlin("1.1") +open class Foo + +class Bar @SinceKotlin("1.1") constructor() + +@SinceKotlin("1.0") +class Baz @SinceKotlin("1.1") constructor() + + +fun t1(): Foo = Foo() + +// TODO: do not report API_NOT_AVAILABLE twice +fun t2() = object : Foo() {} + +fun t3(): Bar? = Bar() + +fun t4(): Baz = Baz() diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/classesAndConstructors.txt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/classesAndConstructors.txt new file mode 100644 index 00000000000..9c89074b1a2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/classesAndConstructors.txt @@ -0,0 +1,27 @@ +package + +public fun t1(): Foo +public fun t2(): Foo +public fun t3(): Bar? +public fun t4(): Baz + +public final class Bar { + @kotlin.SinceKotlin(version = "1.1") public constructor Bar() + 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 +} + +@kotlin.SinceKotlin(version = "1.0") public final class Baz { + @kotlin.SinceKotlin(version = "1.1") public constructor Baz() + 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 +} + +@kotlin.SinceKotlin(version = "1.1") public open class Foo { + public constructor Foo() + 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/sourceCompatibility/apiVersion/overriddenMembers.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/overriddenMembers.kt new file mode 100644 index 00000000000..5a6836588bc --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/overriddenMembers.kt @@ -0,0 +1,34 @@ +// !API_VERSION: 1.0 +// FILE: J.java + +public interface J { + void foo(); +} + +// FILE: test.kt + +interface I10 { + @SinceKotlin("1.0") + fun foo() +} + +interface I11 { + @SinceKotlin("1.1") + fun foo() +} + +fun f1(x: I10) = x.foo() +fun f2(x: I11) = x.foo() +fun f3(x: J) = x.foo() + +interface BothI1 : I10, I11 +fun f4(x: BothI1) = x.foo() + +interface BothI2 : I11, I10 +fun f5(x: BothI2) = x.foo() + +interface JAndI10 : J, I10 +fun f6(x: JAndI10) = x.foo() + +interface JAndI11 : J, I11 +fun f7(x: JAndI11) = x.foo() diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/overriddenMembers.txt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/overriddenMembers.txt new file mode 100644 index 00000000000..461f76d6e5c --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/overriddenMembers.txt @@ -0,0 +1,59 @@ +package + +public /*synthesized*/ fun J(/*0*/ function: () -> kotlin.Unit): J +public fun f1(/*0*/ x: I10): kotlin.Unit +public fun f2(/*0*/ x: I11): [ERROR : Error function type] +public fun f3(/*0*/ x: J): kotlin.Unit +public fun f4(/*0*/ x: BothI1): kotlin.Unit +public fun f5(/*0*/ x: BothI2): kotlin.Unit +public fun f6(/*0*/ x: JAndI10): kotlin.Unit +public fun f7(/*0*/ x: JAndI11): kotlin.Unit + +public interface BothI1 : I10, I11 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.SinceKotlin(version = "1.0") public abstract override /*2*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface BothI2 : I11, I10 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.SinceKotlin(version = "1.1") public abstract override /*2*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface I10 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.SinceKotlin(version = "1.0") public abstract fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface I11 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @kotlin.SinceKotlin(version = "1.1") public abstract fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface J { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface JAndI10 : J, I10 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface JAndI11 : J, I11 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/propertyAccessors.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/propertyAccessors.kt new file mode 100644 index 00000000000..28bfadf4c27 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/propertyAccessors.kt @@ -0,0 +1,48 @@ +// !API_VERSION: 1.0 + +val v1: String + @SinceKotlin("1.1") + get() = "" + +@SinceKotlin("1.1") +val v2 = "" + +var v3: String + @SinceKotlin("1.1") + get() = "" + set(value) {} + +var v4: String + get() = "" + @SinceKotlin("1.1") + set(value) {} + +var v5: String + @SinceKotlin("1.1") + get() = "" + @SinceKotlin("1.1") + set(value) {} + +@SinceKotlin("1.1") +var v6: String + get() = "" + set(value) {} + +@SinceKotlin("1.0") +val v7: String + @SinceKotlin("1.1") + get() = "" + +fun test() { + v1 + v2 + v3 + v3 = "" + v4 + v4 = "" + v5 + v5 = "" + v6 + v6 = "" + v7 +} diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/propertyAccessors.txt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/propertyAccessors.txt new file mode 100644 index 00000000000..e6481973f12 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/propertyAccessors.txt @@ -0,0 +1,10 @@ +package + +public val v1: kotlin.String +@kotlin.SinceKotlin(version = "1.1") public val v2: kotlin.String = "" +public var v3: kotlin.String +public var v4: kotlin.String +public var v5: kotlin.String +@kotlin.SinceKotlin(version = "1.1") public var v6: kotlin.String +@kotlin.SinceKotlin(version = "1.0") public val v7: kotlin.String +public fun test(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/simpleMembers.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/simpleMembers.kt new file mode 100644 index 00000000000..2fb3a53d971 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/simpleMembers.kt @@ -0,0 +1,19 @@ +// !API_VERSION: 1.0 + +@SinceKotlin("1.1") +fun f() {} + +@SinceKotlin("1.1") +var p = Unit + +@SinceKotlin("1.1.2") +fun z() {} + + +fun t1() = f() + +fun t2() = p + +fun t3() { p = Unit } + +fun t4() { z() } diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/simpleMembers.txt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/simpleMembers.txt new file mode 100644 index 00000000000..2f406ad6fc6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/simpleMembers.txt @@ -0,0 +1,9 @@ +package + +@kotlin.SinceKotlin(version = "1.1") public var p: kotlin.Unit +@kotlin.SinceKotlin(version = "1.1") public fun f(): kotlin.Unit +public fun t1(): [ERROR : Error function type] +public fun t2(): [ERROR : Error function type] +public fun t3(): kotlin.Unit +public fun t4(): kotlin.Unit +@kotlin.SinceKotlin(version = "1.1.2") public fun z(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/sinceOldVersionIsOK.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/sinceOldVersionIsOK.kt new file mode 100644 index 00000000000..6d35fbdbbb6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/sinceOldVersionIsOK.kt @@ -0,0 +1,18 @@ +// !API_VERSION: 1.1 + +@SinceKotlin("0.9") +fun ok1() {} + +@SinceKotlin("1.0") +fun ok2() {} + +@SinceKotlin("1.1") +fun ok3() {} + +@SinceKotlin("0.9.9") +fun ok4() {} + +fun t1() = ok1() +fun t2() = ok2() +fun t3() = ok3() +fun t4() = ok4() diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/sinceOldVersionIsOK.txt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/sinceOldVersionIsOK.txt new file mode 100644 index 00000000000..e1fff254c64 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/sinceOldVersionIsOK.txt @@ -0,0 +1,10 @@ +package + +@kotlin.SinceKotlin(version = "0.9") public fun ok1(): kotlin.Unit +@kotlin.SinceKotlin(version = "1.0") public fun ok2(): kotlin.Unit +@kotlin.SinceKotlin(version = "1.1") public fun ok3(): kotlin.Unit +@kotlin.SinceKotlin(version = "0.9.9") public fun ok4(): kotlin.Unit +public fun t1(): kotlin.Unit +public fun t2(): kotlin.Unit +public fun t3(): kotlin.Unit +public fun t4(): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.java b/compiler/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.java index 2465d516bd2..61fddd4fc44 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.java @@ -143,7 +143,7 @@ public abstract class AbstractDiagnosticsTest extends BaseDiagnosticsTest { moduleBindings.put(testModule, moduleTrace.getBindingContext()); - LanguageVersionSettings languageVersionSettings = loadCustomLanguageVersionSettings(testFilesInModule); + LanguageVersionSettings languageVersionSettings = loadLanguageVersionSettings(testFilesInModule); ModuleContext moduleContext = ContextKt.withModule(ContextKt.withProject(context, getProject()), module); boolean separateModules = groupedByModule.size() == 1; @@ -210,17 +210,19 @@ public abstract class AbstractDiagnosticsTest extends BaseDiagnosticsTest { } @Nullable - private LanguageVersionSettings loadCustomLanguageVersionSettings(List module) { + private LanguageVersionSettings loadLanguageVersionSettings(List module) { LanguageVersionSettings result = null; for (TestFile file : module) { - if (file.customLanguageVersionSettings != null) { - if (result != null) { + LanguageVersionSettings current = file.customLanguageVersionSettings; + if (current != null) { + if (result != null && !result.equals(current)) { Assert.fail( - "More than one file in the module has " + BaseDiagnosticsTest.LANGUAGE_DIRECTIVE + " directive specified. " + + "More than one file in the module has " + BaseDiagnosticsTest.LANGUAGE_DIRECTIVE + " or " + + BaseDiagnosticsTest.API_VERSION_DIRECTIVE + " directive specified. " + "This is not supported. Please move all directives into one file" ); } - result = file.customLanguageVersionSettings; + result = current; } } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.java b/compiler/tests/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.java index 83fb516e2c0..c7711f81fd4 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.java @@ -34,6 +34,7 @@ import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.asJava.DuplicateJvmSignatureUtilKt; +import org.jetbrains.kotlin.config.ApiVersion; import org.jetbrains.kotlin.config.LanguageFeature; import org.jetbrains.kotlin.config.LanguageVersionSettings; import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl; @@ -71,6 +72,8 @@ public abstract class BaseDiagnosticsTest public static final String LANGUAGE_DIRECTIVE = "LANGUAGE"; private static final Pattern LANGUAGE_PATTERN = Pattern.compile("([\\+\\-])(\\w+)\\s*"); + public static final String API_VERSION_DIRECTIVE = "API_VERSION"; + public static final String CHECK_TYPE_DIRECTIVE = "CHECK_TYPE"; public static final String CHECK_TYPE_PACKAGE = "tests._checkType"; private static final String CHECK_TYPE_DECLARATIONS = "\npackage " + CHECK_TYPE_PACKAGE + @@ -155,14 +158,26 @@ public abstract class BaseDiagnosticsTest } @Nullable - private static LanguageVersionSettings parseLanguageDirective(Map directiveMap) { + private static LanguageVersionSettings parseLanguageVersionSettings(Map directiveMap) { + String apiVersionString = directiveMap.get(API_VERSION_DIRECTIVE); String directives = directiveMap.get(LANGUAGE_DIRECTIVE); - if (directives == null) return null; + if (apiVersionString == null && directives == null) return null; + ApiVersion apiVersion = apiVersionString != null ? ApiVersion.Companion.parse(apiVersionString) : ApiVersion.LATEST; + assert apiVersion != null : "Unknown API version: " + apiVersionString; + + Map languageFeatures = + directives == null ? Collections.emptyMap() : collectLanguageFeatureMap(directives); + + return new DiagnosticTestLanguageVersionSettings(languageFeatures, apiVersion); + } + + @NotNull + private static Map collectLanguageFeatureMap(@NotNull String directives) { Matcher matcher = LANGUAGE_PATTERN.matcher(directives); if (!matcher.find()) { Assert.fail( - "Wrong syntax in the '// !LANGUAGE: ...' directive:\n" + + "Wrong syntax in the '// !" + LANGUAGE_DIRECTIVE + ": ...' directive:\n" + "found: '" + directives + "'\n" + "Must be '([+-]LanguageFeatureName)+'\n" + "where '+' means 'enable' and '-' means 'disable'\n" + @@ -170,7 +185,7 @@ public abstract class BaseDiagnosticsTest ); } - final Map values = new HashMap(); + Map values = new HashMap(); do { boolean enable = matcher.group(1).equals("+"); String name = matcher.group(2); @@ -187,16 +202,7 @@ public abstract class BaseDiagnosticsTest } while (matcher.find()); - return new LanguageVersionSettings() { - @Override - public boolean supportsFeature(@NotNull LanguageFeature feature) { - Boolean enabled = values.get(feature); - if (enabled != null) { - return enabled; - } - return LanguageVersionSettingsImpl.DEFAULT.supportsFeature(feature); - } - }; + return values; } public static Condition parseDiagnosticFilterDirective(Map directiveMap) { @@ -207,7 +213,7 @@ public abstract class BaseDiagnosticsTest Condition condition = Conditions.alwaysTrue(); Matcher matcher = DIAGNOSTICS_PATTERN.matcher(directives); if (!matcher.find()) { - Assert.fail("Wrong syntax in the '// !DIAGNOSTICS: ...' directive:\n" + + Assert.fail("Wrong syntax in the '// !" + DIAGNOSTICS_DIRECTIVE + ": ...' directive:\n" + "found: '" + directives + "'\n" + "Must be '([+-!]DIAGNOSTIC_FACTORY_NAME|ERROR|WARNING|INFO)+'\n" + "where '+' means 'include'\n" + @@ -289,6 +295,37 @@ public abstract class BaseDiagnosticsTest } } + public static class DiagnosticTestLanguageVersionSettings implements LanguageVersionSettings { + private final Map languageFeatures; + private final ApiVersion apiVersion; + + public DiagnosticTestLanguageVersionSettings( + @NotNull Map languageFeatures, @NotNull ApiVersion apiVersion + ) { + this.languageFeatures = languageFeatures; + this.apiVersion = apiVersion; + } + + @Override + public boolean supportsFeature(@NotNull LanguageFeature feature) { + Boolean enabled = languageFeatures.get(feature); + return enabled != null ? enabled : LanguageVersionSettingsImpl.DEFAULT.supportsFeature(feature); + } + + @NotNull + @Override + public ApiVersion getApiVersion() { + return apiVersion; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof DiagnosticTestLanguageVersionSettings && + ((DiagnosticTestLanguageVersionSettings) obj).languageFeatures.equals(languageFeatures) && + ((DiagnosticTestLanguageVersionSettings) obj).apiVersion.equals(apiVersion); + } + } + protected class TestFile { private final List diagnosedRanges = Lists.newArrayList(); public final String expectedText; @@ -311,7 +348,7 @@ public abstract class BaseDiagnosticsTest ) { this.module = module; this.whatDiagnosticsToConsider = parseDiagnosticFilterDirective(directives); - this.customLanguageVersionSettings = parseLanguageDirective(directives); + this.customLanguageVersionSettings = parseLanguageVersionSettings(directives); this.checkLazyLog = directives.containsKey(CHECK_LAZY_LOG_DIRECTIVE) || CHECK_LAZY_LOG_DEFAULT; this.declareCheckType = directives.containsKey(CHECK_TYPE_DIRECTIVE); this.declareFlexibleType = directives.containsKey(EXPLICIT_FLEXIBLE_TYPES_DIRECTIVE); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 9a6c5479779..637abe57621 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -12383,6 +12383,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("sinceKotlin.kt") + public void testSinceKotlin() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sinceKotlin.kt"); + doTest(fileName); + } + @TestMetadata("substitutedGenericInParams.kt") public void testSubstitutedGenericInParams() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/substitutedGenericInParams.kt"); @@ -12442,6 +12448,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multimodule/hiddenClass/deprecatedHiddenMultipleClasses.kt"); doTest(fileName); } + + @TestMetadata("sinceKotlinImportPriority.kt") + public void testSinceKotlinImportPriority() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinImportPriority.kt"); + doTest(fileName); + } + + @TestMetadata("sinceKotlinMultipleClasses.kt") + public void testSinceKotlinMultipleClasses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multimodule/hiddenClass/sinceKotlinMultipleClasses.kt"); + doTest(fileName); + } } } @@ -19488,6 +19506,51 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ApiVersion extends AbstractDiagnosticsTest { + public void testAllFilesPresentInApiVersion() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("annotations.kt") + public void testAnnotations() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/annotations.kt"); + doTest(fileName); + } + + @TestMetadata("classesAndConstructors.kt") + public void testClassesAndConstructors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/classesAndConstructors.kt"); + doTest(fileName); + } + + @TestMetadata("overriddenMembers.kt") + public void testOverriddenMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/overriddenMembers.kt"); + doTest(fileName); + } + + @TestMetadata("propertyAccessors.kt") + public void testPropertyAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/propertyAccessors.kt"); + doTest(fileName); + } + + @TestMetadata("simpleMembers.kt") + public void testSimpleMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/simpleMembers.kt"); + doTest(fileName); + } + + @TestMetadata("sinceOldVersionIsOK.kt") + public void testSinceOldVersionIsOK() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/sinceOldVersionIsOK.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java index 1b3f881f333..c03a0fdc07e 100644 --- a/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java @@ -37,6 +37,30 @@ public class CliTestGenerated extends AbstractCliTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/cli/jvm"), Pattern.compile("^(.+)\\.args$"), false); } + @TestMetadata("apiVersion.args") + public void testApiVersion() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/apiVersion.args"); + doJvmTest(fileName); + } + + @TestMetadata("apiVersionGreaterThanLanguage.args") + public void testApiVersionGreaterThanLanguage() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/apiVersionGreaterThanLanguage.args"); + doJvmTest(fileName); + } + + @TestMetadata("apiVersionInvalid.args") + public void testApiVersionInvalid() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/apiVersionInvalid.args"); + doJvmTest(fileName); + } + + @TestMetadata("apiVersionLessThanLanguage.args") + public void testApiVersionLessThanLanguage() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/apiVersionLessThanLanguage.args"); + doJvmTest(fileName); + } + @TestMetadata("classAndFileClassClash.args") public void testClassAndFileClassClash() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/classAndFileClassClash.args"); diff --git a/compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt b/compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt index cf5d8bf6007..3ed4d109537 100644 --- a/compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt @@ -40,8 +40,9 @@ class CodeConformanceTest : TestCase() { "libraries/tools/kotlin-gradle-plugin-core/gradle_api_jar/build/tmp", "libraries/tools/kotlin-maven-plugin/target", "compiler/testData/psi/kdoc", - "compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt" - ).map { File(it) } + "compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt", + "compiler/util/src/org/jetbrains/kotlin/config/MavenComparableVersion.java" + ).map(::File) } fun testParserCode() { diff --git a/compiler/util/src/org/jetbrains/kotlin/config/ApiVersion.kt b/compiler/util/src/org/jetbrains/kotlin/config/ApiVersion.kt new file mode 100644 index 00000000000..af29b8528eb --- /dev/null +++ b/compiler/util/src/org/jetbrains/kotlin/config/ApiVersion.kt @@ -0,0 +1,48 @@ +/* + * 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.config + +class ApiVersion private constructor( + private val version: MavenComparableVersion, + val versionString: String +) : Comparable { + override fun compareTo(other: ApiVersion): Int = + version.compareTo(other.version) + + override fun equals(other: Any?) = + (other as? ApiVersion)?.version == version + + override fun hashCode() = + version.hashCode() + + override fun toString() = versionString + + companion object { + @JvmField + val LATEST: ApiVersion = createByLanguageVersion(LanguageVersion.Companion.LATEST) + + @JvmStatic + fun createByLanguageVersion(version: LanguageVersion): ApiVersion = parse(version.versionString)!! + + fun parse(versionString: String): ApiVersion? = try { + ApiVersion(MavenComparableVersion(versionString), versionString) + } + catch (e: Exception) { + null + } + } +} diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 286f5cf330a..2c25fcccefd 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -45,6 +45,8 @@ enum class LanguageVersion(val versionString: String) { KOTLIN_1_0("1.0"), KOTLIN_1_1("1.1"); + override fun toString() = versionString + companion object { @JvmStatic fun fromVersionString(str: String) = values().find { it.versionString == str } @@ -56,15 +58,22 @@ enum class LanguageVersion(val versionString: String) { interface LanguageVersionSettings { fun supportsFeature(feature: LanguageFeature): Boolean + + val apiVersion: ApiVersion } -class LanguageVersionSettingsImpl(private val languageVersion: LanguageVersion) : LanguageVersionSettings { +class LanguageVersionSettingsImpl( + private val languageVersion: LanguageVersion, + override val apiVersion: ApiVersion +) : LanguageVersionSettings { override fun supportsFeature(feature: LanguageFeature): Boolean { - return languageVersion.ordinal >= feature.sinceVersion.ordinal + return languageVersion >= feature.sinceVersion } + override fun toString() = "Language = $languageVersion, API = $apiVersion" + companion object { @JvmField - val DEFAULT = LanguageVersionSettingsImpl(LanguageVersion.LATEST) + val DEFAULT = LanguageVersionSettingsImpl(LanguageVersion.LATEST, ApiVersion.LATEST) } } diff --git a/compiler/util/src/org/jetbrains/kotlin/config/MavenComparableVersion.java b/compiler/util/src/org/jetbrains/kotlin/config/MavenComparableVersion.java new file mode 100644 index 00000000000..e970f8f88d6 --- /dev/null +++ b/compiler/util/src/org/jetbrains/kotlin/config/MavenComparableVersion.java @@ -0,0 +1,504 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.config; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Properties; +import java.util.Stack; + +/** + * Generic implementation of version comparison. + * + *

Features: + *

    + *
  • mixing of '-' (dash) and '.' (dot) separators,
  • + *
  • transition between characters and digits also constitutes a separator: + * 1.0alpha1 => [1, 0, alpha, 1]
  • + *
  • unlimited number of version components,
  • + *
  • version components in the text can be digits or strings,
  • + *
  • strings are checked for well-known qualifiers and the qualifier ordering is used for version ordering. + * Well-known qualifiers (case insensitive) are:
      + *
    • alpha or a
    • + *
    • beta or b
    • + *
    • milestone or m
    • + *
    • rc or cr
    • + *
    • snapshot
    • + *
    • (the empty string) or ga or final
    • + *
    • sp
    • + *
    + * Unknown qualifiers are considered after known qualifiers, with lexical order (always case insensitive), + *
  • + *
  • a dash usually precedes a qualifier, and is always less important than something preceded with a dot.
  • + *

+ * + * @see
"Versioning" on Maven Wiki + * @author Kenney Westerhof + * @author Hervé Boutemy + */ +@SuppressWarnings("ALL") +public class MavenComparableVersion + implements Comparable +{ + private String value; + + private String canonical; + + private ListItem items; + + private interface Item + { + int INTEGER_ITEM = 0; + int STRING_ITEM = 1; + int LIST_ITEM = 2; + + int compareTo( Item item ); + + int getType(); + + boolean isNull(); + } + + /** + * Represents a numeric item in the version item list. + */ + private static class IntegerItem + implements Item + { + private static final BigInteger BIG_INTEGER_ZERO = new BigInteger( "0" ); + + private final BigInteger value; + + public static final IntegerItem ZERO = new IntegerItem(); + + private IntegerItem() + { + this.value = BIG_INTEGER_ZERO; + } + + public IntegerItem( String str ) + { + this.value = new BigInteger( str ); + } + + public int getType() + { + return INTEGER_ITEM; + } + + public boolean isNull() + { + return BIG_INTEGER_ZERO.equals( value ); + } + + public int compareTo( Item item ) + { + if ( item == null ) + { + return BIG_INTEGER_ZERO.equals( value ) ? 0 : 1; // 1.0 == 1, 1.1 > 1 + } + + switch ( item.getType() ) + { + case INTEGER_ITEM: + return value.compareTo( ( (IntegerItem) item ).value ); + + case STRING_ITEM: + return 1; // 1.1 > 1-sp + + case LIST_ITEM: + return 1; // 1.1 > 1-1 + + default: + throw new RuntimeException( "invalid item: " + item.getClass() ); + } + } + + public String toString() + { + return value.toString(); + } + } + + /** + * Represents a string in the version item list, usually a qualifier. + */ + private static class StringItem + implements Item + { + private static final String[] QUALIFIERS = { "alpha", "beta", "milestone", "rc", "snapshot", "", "sp" }; + + @SuppressWarnings( "checkstyle:constantname" ) + private static final List _QUALIFIERS = Arrays.asList( QUALIFIERS ); + + private static final Properties ALIASES = new Properties(); + static + { + ALIASES.put( "ga", "" ); + ALIASES.put( "final", "" ); + ALIASES.put( "cr", "rc" ); + } + + /** + * A comparable value for the empty-string qualifier. This one is used to determine if a given qualifier makes + * the version older than one without a qualifier, or more recent. + */ + private static final String RELEASE_VERSION_INDEX = String.valueOf( _QUALIFIERS.indexOf( "" ) ); + + private String value; + + public StringItem( String value, boolean followedByDigit ) + { + if ( followedByDigit && value.length() == 1 ) + { + // a1 = alpha-1, b1 = beta-1, m1 = milestone-1 + switch ( value.charAt( 0 ) ) + { + case 'a': + value = "alpha"; + break; + case 'b': + value = "beta"; + break; + case 'm': + value = "milestone"; + break; + default: + } + } + this.value = ALIASES.getProperty( value , value ); + } + + public int getType() + { + return STRING_ITEM; + } + + public boolean isNull() + { + return ( comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX ) == 0 ); + } + + /** + * Returns a comparable value for a qualifier. + * + * This method takes into account the ordering of known qualifiers then unknown qualifiers with lexical + * ordering. + * + * just returning an Integer with the index here is faster, but requires a lot of if/then/else to check for -1 + * or QUALIFIERS.size and then resort to lexical ordering. Most comparisons are decided by the first character, + * so this is still fast. If more characters are needed then it requires a lexical sort anyway. + * + * @param qualifier + * @return an equivalent value that can be used with lexical comparison + */ + public static String comparableQualifier( String qualifier ) + { + int i = _QUALIFIERS.indexOf( qualifier ); + + return i == -1 ? ( _QUALIFIERS.size() + "-" + qualifier ) : String.valueOf( i ); + } + + public int compareTo( Item item ) + { + if ( item == null ) + { + // 1-rc < 1, 1-ga > 1 + return comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX ); + } + switch ( item.getType() ) + { + case INTEGER_ITEM: + return -1; // 1.any < 1.1 ? + + case STRING_ITEM: + return comparableQualifier( value ).compareTo( comparableQualifier( ( (StringItem) item ).value ) ); + + case LIST_ITEM: + return -1; // 1.any < 1-1 + + default: + throw new RuntimeException( "invalid item: " + item.getClass() ); + } + } + + public String toString() + { + return value; + } + } + + /** + * Represents a version list item. This class is used both for the global item list and for sub-lists (which start + * with '-(number)' in the version specification). + */ + private static class ListItem + extends ArrayList + implements Item + { + public int getType() + { + return LIST_ITEM; + } + + public boolean isNull() + { + return ( size() == 0 ); + } + + void normalize() + { + for ( int i = size() - 1; i >= 0; i-- ) + { + Item lastItem = get( i ); + + if ( lastItem.isNull() ) + { + // remove null trailing items: 0, "", empty list + remove( i ); + } + else if ( !( lastItem instanceof ListItem ) ) + { + break; + } + } + } + + public int compareTo( Item item ) + { + if ( item == null ) + { + if ( size() == 0 ) + { + return 0; // 1-0 = 1- (normalize) = 1 + } + Item first = get( 0 ); + return first.compareTo( null ); + } + switch ( item.getType() ) + { + case INTEGER_ITEM: + return -1; // 1-1 < 1.0.x + + case STRING_ITEM: + return 1; // 1-1 > 1-sp + + case LIST_ITEM: + Iterator left = iterator(); + Iterator right = ( (ListItem) item ).iterator(); + + while ( left.hasNext() || right.hasNext() ) + { + Item l = left.hasNext() ? left.next() : null; + Item r = right.hasNext() ? right.next() : null; + + // if this is shorter, then invert the compare and mul with -1 + int result = l == null ? ( r == null ? 0 : -1 * r.compareTo( l ) ) : l.compareTo( r ); + + if ( result != 0 ) + { + return result; + } + } + + return 0; + + default: + throw new RuntimeException( "invalid item: " + item.getClass() ); + } + } + + public String toString() + { + StringBuilder buffer = new StringBuilder(); + for ( Iterator iter = iterator(); iter.hasNext(); ) + { + Item item = iter.next(); + if ( buffer.length() > 0 ) + { + buffer.append( ( item instanceof ListItem ) ? '-' : '.' ); + } + buffer.append( item ); + } + return buffer.toString(); + } + } + + public MavenComparableVersion( String version ) + { + parseVersion( version ); + } + + public final void parseVersion( String version ) + { + this.value = version; + + items = new ListItem(); + + version = version.toLowerCase( Locale.ENGLISH ); + + ListItem list = items; + + Stack stack = new Stack(); + stack.push( list ); + + boolean isDigit = false; + + int startIndex = 0; + + for ( int i = 0; i < version.length(); i++ ) + { + char c = version.charAt( i ); + + if ( c == '.' ) + { + if ( i == startIndex ) + { + list.add( IntegerItem.ZERO ); + } + else + { + list.add( parseItem( isDigit, version.substring( startIndex, i ) ) ); + } + startIndex = i + 1; + } + else if ( c == '-' ) + { + if ( i == startIndex ) + { + list.add( IntegerItem.ZERO ); + } + else + { + list.add( parseItem( isDigit, version.substring( startIndex, i ) ) ); + } + startIndex = i + 1; + + list.add( list = new ListItem() ); + stack.push( list ); + } + else if ( Character.isDigit( c ) ) + { + if ( !isDigit && i > startIndex ) + { + list.add( new StringItem( version.substring( startIndex, i ), true ) ); + startIndex = i; + + list.add( list = new ListItem() ); + stack.push( list ); + } + + isDigit = true; + } + else + { + if ( isDigit && i > startIndex ) + { + list.add( parseItem( true, version.substring( startIndex, i ) ) ); + startIndex = i; + + list.add( list = new ListItem() ); + stack.push( list ); + } + + isDigit = false; + } + } + + if ( version.length() > startIndex ) + { + list.add( parseItem( isDigit, version.substring( startIndex ) ) ); + } + + while ( !stack.isEmpty() ) + { + list = (ListItem) stack.pop(); + list.normalize(); + } + + canonical = items.toString(); + } + + private static Item parseItem( boolean isDigit, String buf ) + { + return isDigit ? new IntegerItem( buf ) : new StringItem( buf, false ); + } + + public int compareTo( MavenComparableVersion o ) + { + return items.compareTo( o.items ); + } + + public String toString() + { + return value; + } + + public String getCanonical() + { + return canonical; + } + + public boolean equals( Object o ) + { + return ( o instanceof MavenComparableVersion) && canonical.equals(((MavenComparableVersion) o ).canonical ); + } + + public int hashCode() + { + return canonical.hashCode(); + } + + /** + * Main to test version parsing and comparison. + * + * @param args the version strings to parse and compare + */ + public static void main( String... args ) + { + System.out.println( "Display parameters as parsed by Maven (in canonical form) and comparison result:" ); + if ( args.length == 0 ) + { + return; + } + + MavenComparableVersion prev = null; + int i = 1; + for ( String version : args ) + { + MavenComparableVersion c = new MavenComparableVersion(version ); + + if ( prev != null ) + { + int compare = prev.compareTo( c ); + System.out.println( " " + prev.toString() + ' ' + + ( ( compare == 0 ) ? "==" : ( ( compare < 0 ) ? "<" : ">" ) ) + ' ' + version ); + } + + System.out.println( String.valueOf( i++ ) + ". " + version + " == " + c.getCanonical() ); + + prev = c; + } + } +} diff --git a/core/builtins/src/kotlin/reflect/KClass.kt b/core/builtins/src/kotlin/reflect/KClass.kt index e4bb27d11c1..c7dd12cb519 100644 --- a/core/builtins/src/kotlin/reflect/KClass.kt +++ b/core/builtins/src/kotlin/reflect/KClass.kt @@ -61,6 +61,7 @@ public interface KClass : KDeclarationContainer, KAnnotatedElement, KCl /** * Returns `true` if [value] is an instance of this class on a given platform. */ + @SinceKotlin("1.1") public fun isInstance(value: Any?): Boolean /** diff --git a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDiagnosticMessageJsTest.java b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDiagnosticMessageJsTest.java index 7dbc57641ba..d749be05a76 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDiagnosticMessageJsTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDiagnosticMessageJsTest.java @@ -21,10 +21,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.analyzer.AnalysisResult; import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles; import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; -import org.jetbrains.kotlin.config.CommonConfigurationKeys; -import org.jetbrains.kotlin.config.CompilerConfiguration; -import org.jetbrains.kotlin.config.LanguageVersion; -import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl; +import org.jetbrains.kotlin.config.*; import org.jetbrains.kotlin.idea.test.PluginTestCaseBase; import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS; import org.jetbrains.kotlin.js.config.JSConfigurationKeys; @@ -71,7 +68,8 @@ public abstract class AbstractDiagnosticMessageJsTest extends AbstractDiagnostic configuration.put(CommonConfigurationKeys.DISABLE_INLINE, true); configuration.put(JSConfigurationKeys.UNIT_TEST_CONFIG, true); if (explicitLanguageVersion != null) { - configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, new LanguageVersionSettingsImpl(explicitLanguageVersion)); + configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, + new LanguageVersionSettingsImpl(explicitLanguageVersion, ApiVersion.LATEST)); } return new LibrarySourcesConfig(getProject(), configuration); } diff --git a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDiagnosticMessageTest.java b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDiagnosticMessageTest.java index c2c543c1b8f..eb2f4b5bd99 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDiagnosticMessageTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDiagnosticMessageTest.java @@ -24,10 +24,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.analyzer.AnalysisResult; import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; -import org.jetbrains.kotlin.config.CommonConfigurationKeys; -import org.jetbrains.kotlin.config.CompilerConfiguration; -import org.jetbrains.kotlin.config.LanguageVersion; -import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl; +import org.jetbrains.kotlin.config.*; import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.DiagnosticFactory; import org.jetbrains.kotlin.diagnostics.Errors; @@ -82,7 +79,8 @@ public abstract class AbstractDiagnosticMessageTest extends KotlinTestWithEnviro protected AnalysisResult analyze(@NotNull KtFile file, @Nullable LanguageVersion explicitLanguageVersion) { CompilerConfiguration configuration = getEnvironment().getConfiguration(); if (explicitLanguageVersion != null) { - configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, new LanguageVersionSettingsImpl(explicitLanguageVersion)); + configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, + new LanguageVersionSettingsImpl(explicitLanguageVersion, ApiVersion.LATEST)); } return JvmResolveUtil.analyze(Collections.singleton(file), getEnvironment(), configuration); } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJsOptions.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJsOptions.kt index 7b7a6859731..a47f9644caf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJsOptions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJsOptions.kt @@ -4,6 +4,13 @@ package org.jetbrains.kotlin.gradle.dsl interface KotlinJsOptions { + /** + * Allow to use declarations only from the specified version of bundled libraries + * Possible values: "1.0", "1.1" + * Default value: "1.1" + */ + var apiVersion: kotlin.String + /** * Generate kjsm-files (for creating libraries) * Default value: true diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJsOptionsBase.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJsOptionsBase.kt index 2cb98f71fa7..3ae48f2afbe 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJsOptionsBase.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJsOptionsBase.kt @@ -4,6 +4,11 @@ package org.jetbrains.kotlin.gradle.dsl internal abstract class KotlinJsOptionsBase : org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions { + private var apiVersionField: kotlin.String? = null + override var apiVersion: kotlin.String + get() = apiVersionField ?: "1.1" + set(value) { apiVersionField = value } + private var kjsmField: kotlin.Boolean? = null override var kjsm: kotlin.Boolean get() = kjsmField ?: true @@ -60,6 +65,7 @@ internal abstract class KotlinJsOptionsBase : org.jetbrains.kotlin.gradle.dsl.Ko set(value) { verboseField = value } open fun updateArguments(args: org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments) { + apiVersionField?.let { args.apiVersion = it } kjsmField?.let { args.kjsm = it } languageVersionField?.let { args.languageVersion = it } mainField?.let { args.main = it } @@ -75,6 +81,7 @@ internal abstract class KotlinJsOptionsBase : org.jetbrains.kotlin.gradle.dsl.Ko } internal fun org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments.fillDefaultValues() { + apiVersion = "1.1" kjsm = true languageVersion = "1.1" main = "noCall" diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptions.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptions.kt index 81bc55cea5b..f6ff56cd41c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptions.kt @@ -4,6 +4,13 @@ package org.jetbrains.kotlin.gradle.dsl interface KotlinJvmOptions { + /** + * Allow to use declarations only from the specified version of bundled libraries + * Possible values: "1.0", "1.1" + * Default value: "1.1" + */ + var apiVersion: kotlin.String + /** * Include Kotlin runtime in to resulting .jar * Default value: false diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptionsBase.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptionsBase.kt index 0f17864db23..683c9707694 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptionsBase.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptionsBase.kt @@ -4,6 +4,11 @@ package org.jetbrains.kotlin.gradle.dsl internal abstract class KotlinJvmOptionsBase : org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions { + private var apiVersionField: kotlin.String? = null + override var apiVersion: kotlin.String + get() = apiVersionField ?: "1.1" + set(value) { apiVersionField = value } + private var includeRuntimeField: kotlin.Boolean? = null override var includeRuntime: kotlin.Boolean get() = includeRuntimeField ?: false @@ -50,6 +55,7 @@ internal abstract class KotlinJvmOptionsBase : org.jetbrains.kotlin.gradle.dsl.K set(value) { verboseField = value } open fun updateArguments(args: org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments) { + apiVersionField?.let { args.apiVersion = it } includeRuntimeField?.let { args.includeRuntime = it } jdkHomeField?.let { args.jdkHome = it } jvmTargetField?.let { args.jvmTarget = it } @@ -63,6 +69,7 @@ internal abstract class KotlinJvmOptionsBase : org.jetbrains.kotlin.gradle.dsl.K } internal fun org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments.fillDefaultValues() { + apiVersion = "1.1" includeRuntime = false jdkHome = null jvmTarget = "1.6" diff --git a/license/third_party/maven_LICENSE.txt b/license/third_party/maven_LICENSE.txt new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/license/third_party/maven_LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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.