Put type enhancement improvements under the compiler flag

This commit is contained in:
Victor Petukhov
2020-12-09 12:16:26 +03:00
parent 857cc92326
commit 6f8f531d87
30 changed files with 274 additions and 50 deletions
@@ -137,6 +137,7 @@ fun StorageComponentContainer.configureJavaSpecificComponents(
JavaResolverSettings.create(
isReleaseCoroutines = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
correctNullabilityForNotNullTypeParameter = languageVersionSettings.supportsFeature(LanguageFeature.ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated),
enhancementImprovements = languageVersionSettings.supportsFeature(LanguageFeature.ImprovementsAroundTypeEnhancement),
)
)
@@ -1,4 +1,4 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -0,0 +1,19 @@
// !LANGUAGE: -ImprovementsAroundTypeEnhancement
package test;
import org.jetbrains.annotations.*;
public class Basic_DisabledImprovements {
public interface G<@NotNull T> {
<@NotNull R> void foo(R r);
}
public interface G1<T, E extends T, @NotNull X> {
<R, @Nullable _A extends R> void foo(R r);
}
<R, @NotNull _A extends R, @Nullable K> void foo(R r) {
}
}
@@ -1,4 +1,4 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -1,4 +1,4 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -0,0 +1,30 @@
// !LANGUAGE: -ImprovementsAroundTypeEnhancement
package test;
import org.jetbrains.annotations.*;
public class Basic_DisabledImprovements<T extends @NotNull Object> {
interface G<T> extends G2<@NotNull T, @NotNull String> { }
interface G2<A, B> { }
static class A {
class B<A, B> {}
}
public interface MyClass<TT> {
void f1(G<@NotNull String> p);
G2<@Nullable String, @NotNull Integer> f2();
<T extends @NotNull Object> void f3(@NotNull T x);
void f4(G<@NotNull String @Nullable []> p);
void f5(G<@NotNull ?> p);
void f6(G<@NotNull ? extends @Nullable Object> p);
void f7(G<@NotNull A.B<?, ?>> p);
G<Basic_DisabledImprovements.@Nullable A.B<?, ?>> f81();
G<Basic_DisabledImprovements.A.@Nullable B<?, ?>> f9();
<T extends @NotNull Object, K extends G<@NotNull String []>> void f10(T p);
}
Basic_DisabledImprovements(G<@NotNull String> p) { }
}
@@ -0,0 +1,32 @@
package test
public open class Basic_DisabledImprovements</*0*/ T : @org.jetbrains.annotations.NotNull kotlin.Any!> {
public/*package*/ constructor Basic_DisabledImprovements</*0*/ T : @org.jetbrains.annotations.NotNull kotlin.Any!>(/*0*/ p0: test.Basic_DisabledImprovements.G<@org.jetbrains.annotations.NotNull kotlin.String!>!)
public/*package*/ open class A {
public/*package*/ constructor A()
public/*package*/ open inner class B</*0*/ A : kotlin.Any!, /*1*/ B : kotlin.Any!> {
public/*package*/ constructor B</*0*/ A : kotlin.Any!, /*1*/ B : kotlin.Any!>()
}
}
public/*package*/ interface G</*0*/ T : kotlin.Any!> : test.Basic_DisabledImprovements.G2<@org.jetbrains.annotations.NotNull T!, @org.jetbrains.annotations.NotNull kotlin.String!> {
}
public/*package*/ interface G2</*0*/ A : kotlin.Any!, /*1*/ B : kotlin.Any!> {
}
public interface MyClass</*0*/ TT : kotlin.Any!> {
public abstract fun f1(/*0*/ p0: test.Basic_DisabledImprovements.G<@org.jetbrains.annotations.NotNull kotlin.String!>!): kotlin.Unit
public abstract fun </*0*/ T : @org.jetbrains.annotations.NotNull kotlin.Any!, /*1*/ K : test.Basic_DisabledImprovements.G<kotlin.Array<(out) @org.jetbrains.annotations.NotNull kotlin.String!>!>!> f10(/*0*/ p0: T!): kotlin.Unit
public abstract fun f2(): test.Basic_DisabledImprovements.G2<@org.jetbrains.annotations.Nullable kotlin.String!, @org.jetbrains.annotations.NotNull kotlin.Int!>!
public abstract fun </*0*/ T : @org.jetbrains.annotations.NotNull kotlin.Any!> f3(/*0*/ @org.jetbrains.annotations.NotNull p0: @org.jetbrains.annotations.NotNull T): kotlin.Unit
public abstract fun f4(/*0*/ p0: test.Basic_DisabledImprovements.G<(@org.jetbrains.annotations.Nullable kotlin.Array<@org.jetbrains.annotations.NotNull kotlin.String!>..@org.jetbrains.annotations.Nullable kotlin.Array<out @org.jetbrains.annotations.NotNull kotlin.String!>?)>!): kotlin.Unit
public abstract fun f5(/*0*/ p0: test.Basic_DisabledImprovements.G<*>!): kotlin.Unit
public abstract fun f6(/*0*/ p0: test.Basic_DisabledImprovements.G<out @org.jetbrains.annotations.Nullable kotlin.Any!>!): kotlin.Unit
public abstract fun f7(/*0*/ p0: test.Basic_DisabledImprovements.G<@org.jetbrains.annotations.NotNull test.Basic_DisabledImprovements.A.B<*, *>!>!): kotlin.Unit
public abstract fun f81(): test.Basic_DisabledImprovements.G<@org.jetbrains.annotations.Nullable test.Basic_DisabledImprovements.A.B<*, *>!>!
public abstract fun f9(): test.Basic_DisabledImprovements.G<@org.jetbrains.annotations.Nullable test.Basic_DisabledImprovements.A.B<*, *>!>!
}
}
@@ -1,4 +1,4 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -1,4 +1,4 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -1,4 +1,4 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -1,4 +1,4 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -1,3 +1,5 @@
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
import org.jetbrains.annotations.*;
@@ -1,4 +1,4 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -0,0 +1,19 @@
// !LANGUAGE:
package test;
import org.jetbrains.annotations.*;
public class Basic_DisabledImprovements {
public interface G<@NotNull T> {
<@NotNull R> void foo(R r);
}
public interface G1<T, E extends T, @NotNull X> {
<R, @Nullable _A extends R> void foo(R r);
}
<R, @NotNull _A extends R, @Nullable K> void foo(R r) {
}
}
@@ -1,4 +1,5 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -1,4 +1,5 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -0,0 +1,30 @@
// !LANGUAGE: -ImprovementsAroundTypeEnhancement
package test;
import org.jetbrains.annotations.*;
public class Basic_DisabledImprovements<T extends @NotNull Object> {
interface G<T> extends G2<@NotNull T, @NotNull String> { }
interface G2<A, B> { }
static class A {
class B<A, B> {}
}
public interface MyClass<TT> {
void f1(G<@NotNull String> p);
G2<@Nullable String, @NotNull Integer> f2();
<T extends @NotNull Object> void f3(@NotNull T x);
void f4(G<@NotNull String @Nullable []> p);
void f5(G<@NotNull ?> p);
void f6(G<@NotNull ? extends @Nullable Object> p);
void f7(G<@NotNull A.B<?, ?>> p);
G<Basic_DisabledImprovements.@Nullable A.B<?, ?>> f81();
G<Basic_DisabledImprovements.A.@Nullable B<?, ?>> f9();
<T extends @NotNull Object, K extends G<@NotNull String []>> void f10(T p);
}
Basic_DisabledImprovements(G<@NotNull String> p) { }
}
@@ -0,0 +1,32 @@
package test
public open class Basic_DisabledImprovements</*0*/ T : @org.jetbrains.annotations.NotNull kotlin.Any!> {
public/*package*/ constructor Basic_DisabledImprovements</*0*/ T : @org.jetbrains.annotations.NotNull kotlin.Any!>(/*0*/ p: test.Basic_DisabledImprovements.G<@org.jetbrains.annotations.NotNull kotlin.String>!)
public/*package*/ open class A {
public/*package*/ constructor A()
public/*package*/ open inner class B</*0*/ A : kotlin.Any!, /*1*/ B : kotlin.Any!> {
public/*package*/ constructor B</*0*/ A : kotlin.Any!, /*1*/ B : kotlin.Any!>()
}
}
public/*package*/ interface G</*0*/ T : kotlin.Any!> : test.Basic_DisabledImprovements.G2<@org.jetbrains.annotations.NotNull T!, @org.jetbrains.annotations.NotNull kotlin.String!> {
}
public/*package*/ interface G2</*0*/ A : kotlin.Any!, /*1*/ B : kotlin.Any!> {
}
public interface MyClass</*0*/ TT : kotlin.Any!> {
public abstract fun f1(/*0*/ p: test.Basic_DisabledImprovements.G<@org.jetbrains.annotations.NotNull kotlin.String>!): kotlin.Unit
public abstract fun </*0*/ T : @org.jetbrains.annotations.NotNull kotlin.Any!, /*1*/ K : test.Basic_DisabledImprovements.G<kotlin.Array<(out) @org.jetbrains.annotations.NotNull kotlin.String!>!>!> f10(/*0*/ p: T!): kotlin.Unit
public abstract fun f2(): test.Basic_DisabledImprovements.G2<@org.jetbrains.annotations.Nullable kotlin.String?, @org.jetbrains.annotations.NotNull kotlin.Int>!
public abstract fun </*0*/ T : @org.jetbrains.annotations.NotNull kotlin.Any!> f3(/*0*/ @org.jetbrains.annotations.NotNull x: @org.jetbrains.annotations.NotNull T): kotlin.Unit
public abstract fun f4(/*0*/ p: test.Basic_DisabledImprovements.G<(@org.jetbrains.annotations.Nullable kotlin.Array<@org.jetbrains.annotations.NotNull kotlin.String!>..@org.jetbrains.annotations.Nullable kotlin.Array<out @org.jetbrains.annotations.NotNull kotlin.String!>?)>!): kotlin.Unit
public abstract fun f5(/*0*/ p: test.Basic_DisabledImprovements.G<*>!): kotlin.Unit
public abstract fun f6(/*0*/ p: test.Basic_DisabledImprovements.G<out @org.jetbrains.annotations.Nullable kotlin.Any?>!): kotlin.Unit
public abstract fun f7(/*0*/ p: test.Basic_DisabledImprovements.G<@org.jetbrains.annotations.NotNull test.Basic_DisabledImprovements.A.B<*, *>>!): kotlin.Unit
public abstract fun f8(): test.Basic_DisabledImprovements.G<test.Basic_DisabledImprovements.A.B<*, *>!>!
public abstract fun f9(): test.Basic_DisabledImprovements.G<@org.jetbrains.annotations.Nullable test.Basic_DisabledImprovements.A.B<*, *>?>!
}
}
@@ -1,4 +1,5 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -1,4 +1,5 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -1,4 +1,5 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -1,4 +1,5 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -1,4 +1,5 @@
// JAVAC_EXPECTED_FILE
// !LANGUAGE: +ImprovementsAroundTypeEnhancement
package test;
@@ -41,6 +41,7 @@ import java.io.IOException;
import java.util.*;
import java.util.regex.Pattern;
import static org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettingsKt.parseLanguageVersionSettings;
import static org.jetbrains.kotlin.jvm.compiler.LoadDescriptorUtil.*;
import static org.jetbrains.kotlin.test.KotlinTestUtils.compileKotlinWithJava;
import static org.jetbrains.kotlin.test.KotlinTestUtils.newConfiguration;
@@ -85,7 +86,7 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
List<File> javaSources = FileUtil.findFilesByMask(Pattern.compile(".+\\.java"), sourcesDir);
Pair<PackageViewDescriptor, BindingContext> binaryPackageAndContext = compileJavaAndLoadTestPackageAndBindingContextFromBinary(
javaSources, tmpdir, ConfigurationKind.JDK_ONLY
javaSources, tmpdir, ConfigurationKind.JDK_ONLY, null
);
checkJavaPackage(expectedFile, binaryPackageAndContext.first, binaryPackageAndContext.second, COMPARATOR_CONFIGURATION);
@@ -175,7 +176,7 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
public static void updateConfigurationWithDirectives(String content, CompilerConfiguration configuration) {
Directives directives = KotlinTestUtils.parseDirectives(content);
LanguageVersionSettings languageVersionSettings = CompilerTestLanguageVersionSettingsKt.parseLanguageVersionSettings(directives);
LanguageVersionSettings languageVersionSettings = parseLanguageVersionSettings(directives);
if (languageVersionSettings == null) {
languageVersionSettings = CompilerTestLanguageVersionSettingsKt.defaultLanguageVersionSettings();
}
@@ -274,9 +275,12 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
assertTrue(testPackageDir.mkdir());
FileUtil.copy(originalJavaFile, new File(testPackageDir, originalJavaFile.getName()));
Directives directives = KotlinTestUtils.parseDirectives(FileUtil.loadFile(originalJavaFile));
LanguageVersionSettings languageVersionSettings = parseLanguageVersionSettings(directives);
Pair<PackageViewDescriptor, BindingContext> javaPackageAndContext = loadTestPackageAndBindingContextFromJavaRoot(
tmpdir, getTestRootDisposable(), getJdkKind(), ConfigurationKind.JDK_ONLY, false,
false, useJavacWrapper(), withForeignAnnotations(), null);
false, useJavacWrapper(), withForeignAnnotations(), languageVersionSettings);
checkJavaPackage(
expectedFile, javaPackageAndContext.first, javaPackageAndContext.second,
@@ -289,9 +293,10 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
File compiledDir = new File(tmpdir, "compiled");
assertTrue(srcDir.mkdir());
assertTrue(compiledDir.mkdir());
String fileContent = FileUtil.loadFile(new File(javaFileName));
List<File> srcFiles = TestFiles.createTestFiles(
new File(javaFileName).getName(), FileUtil.loadFile(new File(javaFileName), true),
new File(javaFileName).getName(), fileContent,
new TestFiles.TestFileFactoryNoModules<File>() {
@NotNull
@Override
@@ -307,8 +312,11 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
}
});
Directives directives = KotlinTestUtils.parseDirectives(fileContent);
LanguageVersionSettings languageVersionSettings = parseLanguageVersionSettings(directives);
Pair<PackageViewDescriptor, BindingContext> javaPackageAndContext = compileJavaAndLoadTestPackageAndBindingContextFromBinary(
srcFiles, compiledDir, ConfigurationKind.ALL
srcFiles, compiledDir, ConfigurationKind.ALL, languageVersionSettings
);
@@ -329,11 +337,12 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
private Pair<PackageViewDescriptor, BindingContext> compileJavaAndLoadTestPackageAndBindingContextFromBinary(
@NotNull Collection<File> javaFiles,
@NotNull File outDir,
@NotNull ConfigurationKind configurationKind
@NotNull ConfigurationKind configurationKind,
@Nullable LanguageVersionSettings explicitLanguageVersionSettings
) throws IOException {
compileJavaWithAnnotationsJar(javaFiles, outDir, getAdditionalJavacArgs(), getJdkHomeForJavac(), withForeignAnnotations());
return loadTestPackageAndBindingContextFromJavaRoot(outDir, getTestRootDisposable(), getJdkKind(), configurationKind, true,
usePsiClassFilesReading(), useJavacWrapper(), withForeignAnnotations(), null,
usePsiClassFilesReading(), useJavacWrapper(), withForeignAnnotations(), explicitLanguageVersionSettings,
getExtraClasspath(), this::configureEnvironment);
}
@@ -145,6 +145,20 @@ enum class LanguageFeature(
AllowSealedInheritorsInDifferentFilesOfSamePackage(KOTLIN_1_5),
SealedInterfaces(KOTLIN_1_5),
/*
* Improvements include the following:
* - taking into account for type enhancement freshly supported type use annotations: KT-11454
* - use annotations in the type parameter position to enhance corresponding types: KT-11454
* - proper support of the type enhancement of the annotated java arrays: KT-24392
* - proper support of the type enhancement of the annotated java varargs' elements: KT-18768
* - type enhancement based on annotated bounds of type parameters
* - type enhancement within type arguments of the base classes and interfaces
* - support type enhancement based on type use annotations on java fields
* - preference of a type use annotation to annotation of another type: KT-24392
* (if @NotNull has TYPE_USE and METHOD target, then `@NotNull Integer []` -> `Array<Int>..Array<out Int>?` instead of `Array<Int>..Array<out Int>`)
*/
ImprovementsAroundTypeEnhancement(KOTLIN_1_6),
// Temporarily disabled, see KT-27084/KT-22379
SoundSmartcastFromLoopConditionForLoopAssignedVariables(sinceVersion = null, kind = BUG_FIX),
@@ -162,6 +176,7 @@ enum class LanguageFeature(
MultiPlatformProjects(sinceVersion = null, defaultState = State.DISABLED),
NewInference(sinceVersion = KOTLIN_1_4),
// In the next block, features can be enabled only along with new inference
SamConversionForKotlinFunctions(sinceVersion = KOTLIN_1_4),
SamConversionPerArgument(sinceVersion = KOTLIN_1_4),
@@ -263,6 +278,7 @@ enum class LanguageVersion(val major: Int, val minor: Int) : DescriptionAware {
KOTLIN_1_3(1, 3),
KOTLIN_1_4(1, 4),
KOTLIN_1_5(1, 5),
KOTLIN_1_6(1, 6),
;
val isStable: Boolean
@@ -25,10 +25,11 @@ import org.jetbrains.kotlin.name.FqName
class LazyJavaAnnotations(
private val c: LazyJavaResolverContext,
private val annotationOwner: JavaAnnotationOwner
private val annotationOwner: JavaAnnotationOwner,
private val areAnnotationsFreshlySupported: Boolean = false
) : Annotations {
private val annotationDescriptors = c.components.storageManager.createMemoizedFunctionWithNullableValues { annotation: JavaAnnotation ->
JavaAnnotationMapper.mapOrResolveJavaAnnotation(annotation, c)
JavaAnnotationMapper.mapOrResolveJavaAnnotation(annotation, c, areAnnotationsFreshlySupported)
}
override fun findAnnotation(fqName: FqName) =
@@ -31,8 +31,6 @@ import org.jetbrains.kotlin.load.java.components.SignaturePropagator
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeResolver
import org.jetbrains.kotlin.load.java.sources.JavaSourceElementFactory
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameterListOwner
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifierWithMigrationStatus
import org.jetbrains.kotlin.load.java.typeEnhancement.SignatureEnhancement
import org.jetbrains.kotlin.load.kotlin.DeserializedDescriptorResolver
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
@@ -42,7 +40,6 @@ import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
import org.jetbrains.kotlin.utils.JavaTypeEnhancementState
import java.util.*
class JavaResolverComponents(
val storageManager: StorageManager,
@@ -84,6 +81,7 @@ class JavaResolverComponents(
interface JavaResolverSettings {
val isReleaseCoroutines: Boolean
val correctNullabilityForNotNullTypeParameter: Boolean
val enhancementImprovements: Boolean
object Default : JavaResolverSettings {
override val isReleaseCoroutines: Boolean
@@ -91,16 +89,21 @@ interface JavaResolverSettings {
override val correctNullabilityForNotNullTypeParameter: Boolean
get() = false
override val enhancementImprovements: Boolean
get() = false
}
companion object {
fun create(
isReleaseCoroutines: Boolean,
correctNullabilityForNotNullTypeParameter: Boolean
correctNullabilityForNotNullTypeParameter: Boolean,
enhancementImprovements: Boolean,
): JavaResolverSettings =
object : JavaResolverSettings {
override val isReleaseCoroutines get() = isReleaseCoroutines
override val correctNullabilityForNotNullTypeParameter get() = correctNullabilityForNotNullTypeParameter
override val enhancementImprovements get() = enhancementImprovements
}
}
}
@@ -172,9 +175,11 @@ private fun LazyJavaResolverContext.extractDefaultNullabilityQualifier(
return null
}
val areImprovementsEnabled = components.settings.typeEnhancementImprovements
val nullabilityQualifier =
components.signatureEnhancement.extractNullability(typeQualifier)?.copy(isForWarningOnly = jsr305State.isWarning)
?: return null
components.signatureEnhancement.extractNullability(typeQualifier, areImprovementsEnabled, typeParameterBounds = false)
?.copy(isForWarningOnly = jsr305State.isWarning) ?: return null
return JavaDefaultQualifiers(nullabilityQualifier, applicability)
}
@@ -208,7 +208,11 @@ class LazyJavaClassDescriptor(
for (javaType in javaTypes) {
val kotlinType = c.typeResolver.transformJavaType(javaType, TypeUsage.SUPERTYPE.toAttributes())
val enhancedKotlinType = c.components.signatureEnhancement.enhanceSuperType(kotlinType, c)
val areImprovementsEnabled = c.components.settings.typeEnhancementImprovements
val enhancedKotlinType = if (areImprovementsEnabled) {
c.components.signatureEnhancement.enhanceSuperType(kotlinType, c)
} else kotlinType
if (enhancedKotlinType.constructor.declarationDescriptor is NotFoundClasses.MockClassDescriptor) {
incomplete.add(javaType)
}
@@ -62,7 +62,7 @@ class JavaTypeResolver(
fun transformArrayType(arrayType: JavaArrayType, attr: JavaTypeAttributes, isVararg: Boolean = false): KotlinType {
val javaComponentType = arrayType.componentType
val primitiveType = (javaComponentType as? JavaPrimitiveType)?.type
val annotations = LazyJavaAnnotations(c, arrayType)
val annotations = LazyJavaAnnotations(c, arrayType, areAnnotationsFreshlySupported = true)
if (primitiveType != null) {
val jetType = c.module.builtIns.getPrimitiveArrayKotlinType(primitiveType)
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.load.java.*
import org.jetbrains.kotlin.load.java.descriptors.*
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.copyWithNewDefaultTypeQualifiers
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaAnnotationDescriptor
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaTypeParameterDescriptor
import org.jetbrains.kotlin.load.java.lazy.descriptors.isJavaField
import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
@@ -52,21 +53,25 @@ class SignatureEnhancement(
private val typeEnhancement: JavaTypeEnhancement
) {
private fun AnnotationDescriptor.extractNullabilityTypeFromArgument(): NullabilityQualifierWithMigrationStatus? {
private fun AnnotationDescriptor.extractNullabilityTypeFromArgument(isForWarningOnly: Boolean): NullabilityQualifierWithMigrationStatus? {
val enumValue = firstArgument() as? EnumValue
// if no argument is specified, use default value: NOT_NULL
?: return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
?: return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL, isForWarningOnly)
return when (enumValue.enumEntryName.asString()) {
"ALWAYS" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
"MAYBE", "NEVER" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
"UNKNOWN" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.FORCE_FLEXIBILITY)
"ALWAYS" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL, isForWarningOnly)
"MAYBE", "NEVER" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE, isForWarningOnly)
"UNKNOWN" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.FORCE_FLEXIBILITY, isForWarningOnly)
else -> null
}
}
fun extractNullability(annotationDescriptor: AnnotationDescriptor): NullabilityQualifierWithMigrationStatus? {
extractNullabilityFromKnownAnnotations(annotationDescriptor)?.let { return it }
fun extractNullability(
annotationDescriptor: AnnotationDescriptor,
areImprovementsEnabled: Boolean,
typeParameterBounds: Boolean
): NullabilityQualifierWithMigrationStatus? {
extractNullabilityFromKnownAnnotations(annotationDescriptor, areImprovementsEnabled, typeParameterBounds)?.let { return it }
val typeQualifierAnnotation =
annotationTypeQualifierResolver.resolveTypeQualifierAnnotation(annotationDescriptor)
@@ -75,18 +80,23 @@ class SignatureEnhancement(
val jsr305State = annotationTypeQualifierResolver.resolveJsr305AnnotationState(annotationDescriptor)
if (jsr305State.isIgnore) return null
return extractNullabilityFromKnownAnnotations(typeQualifierAnnotation)?.copy(isForWarningOnly = jsr305State.isWarning)
return extractNullabilityFromKnownAnnotations(typeQualifierAnnotation, areImprovementsEnabled, typeParameterBounds)
?.copy(isForWarningOnly = jsr305State.isWarning)
}
private fun extractNullabilityFromKnownAnnotations(
annotationDescriptor: AnnotationDescriptor
annotationDescriptor: AnnotationDescriptor,
areImprovementsEnabled: Boolean,
typeParameterBounds: Boolean
): NullabilityQualifierWithMigrationStatus? {
val annotationFqName = annotationDescriptor.fqName ?: return null
val isForWarningOnly = annotationDescriptor is LazyJavaAnnotationDescriptor
&& (annotationDescriptor.isFreshlySupportedTypeUseAnnotation || typeParameterBounds)
&& !areImprovementsEnabled
val migrationStatus =
jspecifyMigrationStatus(annotationFqName)
?: commonMigrationStatus(annotationFqName, annotationDescriptor)
?: return null
val migrationStatus = jspecifyMigrationStatus(annotationFqName)
?: commonMigrationStatus(annotationFqName, annotationDescriptor, isForWarningOnly)
?: return null
return if (!migrationStatus.isForWarningOnly
&& annotationDescriptor is PossiblyExternalAnnotationDescriptor
@@ -111,17 +121,18 @@ class SignatureEnhancement(
private fun commonMigrationStatus(
annotationFqName: FqName,
annotationDescriptor: AnnotationDescriptor
annotationDescriptor: AnnotationDescriptor,
isForWarningOnly: Boolean = false
): NullabilityQualifierWithMigrationStatus? = when {
annotationFqName in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
annotationFqName in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
annotationFqName == JAVAX_NONNULL_ANNOTATION -> annotationDescriptor.extractNullabilityTypeFromArgument()
annotationFqName in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE, isForWarningOnly)
annotationFqName in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL, isForWarningOnly)
annotationFqName == JAVAX_NONNULL_ANNOTATION -> annotationDescriptor.extractNullabilityTypeFromArgument(isForWarningOnly)
annotationFqName == COMPATQUAL_NULLABLE_ANNOTATION && javaTypeEnhancementState.enableCompatqualCheckerFrameworkAnnotations ->
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE, isForWarningOnly)
annotationFqName == COMPATQUAL_NONNULL_ANNOTATION && javaTypeEnhancementState.enableCompatqualCheckerFrameworkAnnotations ->
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL, isForWarningOnly)
annotationFqName == ANDROIDX_RECENTLY_NON_NULL_ANNOTATION -> NullabilityQualifierWithMigrationStatus(
NullabilityQualifier.NOT_NULL,
@@ -326,10 +337,10 @@ class SignatureEnhancement(
typeParameterForArgument: TypeParameterDescriptor?,
isFromStarProjection: Boolean
): JavaTypeQualifiers {
val areImprovementsEnabled = containerContext.components.settings.typeEnhancementImprovements
val composedAnnotation =
if (isHeadTypeConstructor && typeContainer is TypeParameterDescriptor) {
composeAnnotations(typeContainer.annotations, annotations)
} else if (isHeadTypeConstructor && typeContainer != null) {
if (isHeadTypeConstructor && typeContainer != null && typeContainer !is TypeParameterDescriptor && areImprovementsEnabled) {
val filteredContainerAnnotations = typeContainer.annotations.filter {
val (_, targets) = annotationTypeQualifierResolver.resolveAnnotation(it) ?: return@filter false
/*
@@ -343,6 +354,8 @@ class SignatureEnhancement(
AnnotationQualifierApplicabilityType.TYPE_USE !in targets
}
composeAnnotations(Annotations.create(filteredContainerAnnotations), annotations)
} else if (isHeadTypeConstructor && typeContainer != null) {
composeAnnotations(typeContainer.annotations, annotations)
} else annotations
fun <T : Any> List<FqName>.ifPresent(qualifier: T) =
@@ -361,7 +374,8 @@ class SignatureEnhancement(
val (nullabilityFromBoundsForTypeBasedOnTypeParameter, isTypeParameterWithNotNullableBounds) =
nullabilityInfoBoundsForTypeParameterUsage()
val annotationsNullability = composedAnnotation.extractNullability()?.takeUnless { isFromStarProjection }
val annotationsNullability = composedAnnotation.extractNullability(areImprovementsEnabled, typeParameterBounds)
?.takeUnless { isFromStarProjection }
val nullabilityInfo =
annotationsNullability
?: computeNullabilityInfoInTheAbsenceOfExplicitAnnotation(
@@ -452,8 +466,11 @@ class SignatureEnhancement(
}
}
private fun Annotations.extractNullability(): NullabilityQualifierWithMigrationStatus? =
this.firstNotNullResult { extractNullability(it) }
private fun Annotations.extractNullability(
areImprovementsEnabled: Boolean,
typeParameterBounds: Boolean
): NullabilityQualifierWithMigrationStatus? =
this.firstNotNullResult { extractNullability(it, areImprovementsEnabled, typeParameterBounds) }
private fun computeIndexedQualifiersForOverride(): (Int) -> JavaTypeQualifiers {