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
This commit is contained in:
Alexander Udalov
2016-09-26 19:56:22 +03:00
parent e3df8ed2fe
commit 167ab1f860
59 changed files with 1758 additions and 57 deletions
@@ -30,6 +30,11 @@ public abstract class CommonCompilerArguments {
@ValueDescription("<version>")
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("<version>")
public String apiVersion;
@GradleOption(DefaultValues.BooleanFalseDefault.class)
@Argument(value = "nowarn", description = "Generate no warnings")
public boolean suppressWarnings;
@@ -248,27 +248,58 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
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<String> versionStrings = ArraysKt.map(LanguageVersion.values(), new Function1<LanguageVersion, String>() {
@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<String> versionStrings = ArraysKt.map(LanguageVersion.values(), new Function1<LanguageVersion, String>() {
@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
);
@@ -73,6 +73,11 @@ public interface Errors {
DiagnosticFactory1<KtReferenceExpression, KtReferenceExpression> UNRESOLVED_REFERENCE =
DiagnosticFactory1.create(ERROR, FOR_UNRESOLVED_REFERENCE);
DiagnosticFactory2<PsiElement, DeclarationDescriptor, String> DEPRECATION = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<PsiElement, DeclarationDescriptor, String> DEPRECATION_ERROR = DiagnosticFactory2.create(ERROR);
DiagnosticFactory2<PsiElement, String, String> 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<KtSimpleNameExpression, DeclarationDescriptor, Visibility, DeclarationDescriptor> INVISIBLE_REFERENCE =
@@ -278,9 +283,6 @@ public interface Errors {
DiagnosticFactory0<KtObjectDeclaration> MANY_COMPANION_OBJECTS = DiagnosticFactory0.create(ERROR, COMPANION_OBJECT);
DiagnosticFactory2<PsiElement, DeclarationDescriptor, String> DEPRECATION = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<PsiElement, DeclarationDescriptor, String> DEPRECATION_ERROR = DiagnosticFactory2.create(ERROR);
// Objects
DiagnosticFactory1<KtObjectDeclaration, ClassDescriptor> LOCAL_OBJECT_NOT_ALLOWED = DiagnosticFactory1.create(ERROR, DECLARATION_NAME);
@@ -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");
@@ -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<AdditionalTypeChecker>()
private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf(DeprecatedClassifierUsageChecker())
private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf(DeprecatedClassifierUsageChecker(), ApiVersionClassifierUsageChecker)
abstract class PlatformConfigurator(
@@ -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) }
}
}
}
@@ -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<KtBinaryExpression>(expression, KtBinaryExpression::class.java)
if (binaryExpression != null) {
@@ -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))
}
}
}
@@ -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()
}
@@ -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()
}
+1
View File
@@ -13,6 +13,7 @@ where possible options include:
-output-prefix <path> Path to file which will be added to the beginning of output file
-output-postfix <path> Path to file which will be added to the end of output file
-language-version <version> Provide source compatibility with specified language version
-api-version <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
+5
View File
@@ -0,0 +1,5 @@
$TESTDATA_DIR$/apiVersion.kt
-d
$TEMP_DIR$
-api-version
1.0
+3
View File
@@ -0,0 +1,3 @@
fun test() {
""::class.isInstance(42)
}
+4
View File
@@ -0,0 +1,4 @@
compiler/testData/cli/jvm/apiVersion.kt:2:15: error: unresolved reference: isInstance
""::class.isInstance(42)
^
COMPILATION_ERROR
@@ -0,0 +1,7 @@
$TESTDATA_DIR$/apiVersion.kt
-d
$TEMP_DIR$
-api-version
1.1
-language-version
1.0
@@ -0,0 +1,2 @@
error: -api-version (1.1) cannot be greater than -language-version (1.0)
COMPILATION_ERROR
+5
View File
@@ -0,0 +1,5 @@
$TESTDATA_DIR$/simple.kt
-d
$TEMP_DIR$
-api-version
239.42
+3
View File
@@ -0,0 +1,3 @@
error: unknown API version: 239.42
Supported API versions: 1.0, 1.1
COMPILATION_ERROR
@@ -0,0 +1,7 @@
$TESTDATA_DIR$/apiVersion.kt
-d
$TEMP_DIR$
-api-version
1.0
-language-version
1.1
@@ -0,0 +1,4 @@
compiler/testData/cli/jvm/apiVersion.kt:2:15: error: unresolved reference: isInstance
""::class.isInstance(42)
^
COMPILATION_ERROR
+1
View File
@@ -15,6 +15,7 @@ where possible options include:
-module-name Module name
-jvm-target <version> Target version of the generated JVM bytecode (1.6 or 1.8), default is 1.6
-language-version <version> Provide source compatibility with specified language version
-api-version <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
+4
View File
@@ -3,3 +3,7 @@ package test
sealed class Base
class Derived : Base()
fun test() {
""::class.isInstance(42)
}
+6
View File
@@ -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
+1
View File
@@ -16,6 +16,7 @@ where possible options include:
-module-name Module name
-jvm-target <version> Target version of the generated JVM bytecode (1.6 or 1.8), default is 1.6
-language-version <version> Provide source compatibility with specified language version
-api-version <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
+8
View File
@@ -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
@@ -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
}
@@ -0,0 +1,29 @@
// -- Module: <m1> --
package
package p1 {
@kotlin.SinceKotlin(version = "1.1") public fun foo(/*0*/ s: kotlin.Int): kotlin.String
}
// -- Module: <m2> --
package
package p2 {
public fun foo(/*0*/ s: kotlin.Int): kotlin.Int
}
// -- Module: <m3> --
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
}
@@ -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.<!UNRESOLVED_REFERENCE!>m1<!>()
a.m2()
}
// FILE: explicitlyImportP1.kt
import p1.<!API_NOT_AVAILABLE!>A<!>
import p2.*
fun test(a: <!API_NOT_AVAILABLE!>A<!>) {
a.m1()
a.<!UNRESOLVED_REFERENCE!>m2<!>()
}
@@ -0,0 +1,49 @@
// -- Module: <m1> --
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: <m2> --
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: <m3> --
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: <m1> --
}
}
package p2 {
public final class A {
// -- Module: <m2> --
}
}
@@ -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.<!API_NOT_AVAILABLE!>A<!>
import p3.*
fun test(a: <!API_NOT_AVAILABLE!>A<!>) {
a.<!UNRESOLVED_REFERENCE!>v1<!>
a.v2
a.<!UNRESOLVED_REFERENCE!>v3<!>
}
// FILE: severalStarImports.kt
import p1.*
import p2.*
import p3.*
fun test(a: <!UNRESOLVED_REFERENCE!>A<!>) {
<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!>.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>v1<!>
<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!>.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>v2<!>
<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!>.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>v3<!>
}
@@ -0,0 +1,71 @@
// -- Module: <m1> --
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: <m2> --
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: <m3> --
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: <m4> --
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: <m1> --
}
}
package p2 {
@kotlin.SinceKotlin(version = "1.1") public final class A {
// -- Module: <m2> --
}
}
package p3 {
@kotlin.SinceKotlin(version = "1.1") public final class A {
// -- Module: <m3> --
}
}
@@ -0,0 +1,11 @@
// !API_VERSION: 1.0
@SinceKotlin("1.1")
annotation class Anno1(val s: String)
annotation class Anno2 @SinceKotlin("1.1") constructor()
@<!UNRESOLVED_REFERENCE, API_NOT_AVAILABLE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>Anno1<!>("")
@<!UNRESOLVED_REFERENCE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>Anno2<!>
fun t1() {}
@@ -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
}
@@ -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(): <!API_NOT_AVAILABLE!>Foo<!> = <!UNRESOLVED_REFERENCE!>Foo<!>()
// TODO: do not report API_NOT_AVAILABLE twice
fun t2() = object : <!UNRESOLVED_REFERENCE, API_NOT_AVAILABLE, API_NOT_AVAILABLE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>Foo<!>() {}
fun t3(): Bar? = <!UNRESOLVED_REFERENCE!>Bar<!>()
fun t4(): Baz = <!UNRESOLVED_REFERENCE!>Baz<!>()
@@ -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
}
@@ -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.<!UNRESOLVED_REFERENCE!>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()
@@ -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
}
@@ -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() {
<!API_NOT_AVAILABLE!>v1<!>
<!UNRESOLVED_REFERENCE!>v2<!>
<!API_NOT_AVAILABLE!>v3<!>
v3 = ""
v4
<!API_NOT_AVAILABLE!>v4<!> = ""
<!API_NOT_AVAILABLE!>v5<!>
<!API_NOT_AVAILABLE!>v5<!> = ""
<!UNRESOLVED_REFERENCE!>v6<!>
<!UNRESOLVED_REFERENCE!>v6<!> = ""
<!API_NOT_AVAILABLE!>v7<!>
}
@@ -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
@@ -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() = <!UNRESOLVED_REFERENCE!>f<!>()
fun t2() = <!UNRESOLVED_REFERENCE!>p<!>
fun t3() { <!UNRESOLVED_REFERENCE!>p<!> = Unit }
fun t4() { <!UNRESOLVED_REFERENCE!>z<!>() }
@@ -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
@@ -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()
@@ -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
@@ -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<? extends TestFile> module) {
private LanguageVersionSettings loadLanguageVersionSettings(List<? extends TestFile> 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;
}
}
@@ -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<String, String> directiveMap) {
private static LanguageVersionSettings parseLanguageVersionSettings(Map<String, String> 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<LanguageFeature, Boolean> languageFeatures =
directives == null ? Collections.<LanguageFeature, Boolean>emptyMap() : collectLanguageFeatureMap(directives);
return new DiagnosticTestLanguageVersionSettings(languageFeatures, apiVersion);
}
@NotNull
private static Map<LanguageFeature, Boolean> 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<LanguageFeature, Boolean> values = new HashMap<LanguageFeature, Boolean>();
Map<LanguageFeature, Boolean> values = new HashMap<LanguageFeature, Boolean>();
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<Diagnostic> parseDiagnosticFilterDirective(Map<String, String> directiveMap) {
@@ -207,7 +213,7 @@ public abstract class BaseDiagnosticsTest
Condition<Diagnostic> 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<LanguageFeature, Boolean> languageFeatures;
private final ApiVersion apiVersion;
public DiagnosticTestLanguageVersionSettings(
@NotNull Map<LanguageFeature, Boolean> 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<CheckerTestUtil.DiagnosedRange> 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);
@@ -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)
@@ -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");
@@ -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() {
@@ -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<ApiVersion> {
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
}
}
}
@@ -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)
}
}
@@ -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.
*
* <p>Features:
* <ul>
* <li>mixing of '<code>-</code>' (dash) and '<code>.</code>' (dot) separators,</li>
* <li>transition between characters and digits also constitutes a separator:
* <code>1.0alpha1 =&gt; [1, 0, alpha, 1]</code></li>
* <li>unlimited number of version components,</li>
* <li>version components in the text can be digits or strings,</li>
* <li>strings are checked for well-known qualifiers and the qualifier ordering is used for version ordering.
* Well-known qualifiers (case insensitive) are:<ul>
* <li><code>alpha</code> or <code>a</code></li>
* <li><code>beta</code> or <code>b</code></li>
* <li><code>milestone</code> or <code>m</code></li>
* <li><code>rc</code> or <code>cr</code></li>
* <li><code>snapshot</code></li>
* <li><code>(the empty string)</code> or <code>ga</code> or <code>final</code></li>
* <li><code>sp</code></li>
* </ul>
* Unknown qualifiers are considered after known qualifiers, with lexical order (always case insensitive),
* </li>
* <li>a dash usually precedes a qualifier, and is always less important than something preceded with a dot.</li>
* </ul></p>
*
* @see <a href="https://cwiki.apache.org/confluence/display/MAVENOLD/Versioning">"Versioning" on Maven Wiki</a>
* @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
* @author <a href="mailto:hboutemy@apache.org">Hervé Boutemy</a>
*/
@SuppressWarnings("ALL")
public class MavenComparableVersion
implements Comparable<MavenComparableVersion>
{
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<String> _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<Item>
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<Item> left = iterator();
Iterator<Item> 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<Item> 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<Item> stack = new Stack<Item>();
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;
}
}
}
@@ -61,6 +61,7 @@ public interface KClass<T : Any> : 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
/**
@@ -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);
}
@@ -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);
}
@@ -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
@@ -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"
@@ -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
@@ -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"
+202
View File
@@ -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.