Propagate nullability changes to enhancement for JSR-305 types

Fix TypeUtils.makeNullableAsSpecified for SimpleTypeWithEnhancement and
FlexibleTypeWithEnhancement: change nullability of enhancement too. This
fixes several false-positive warnings, like in KT-20855 and KT-20466.

Note that it removes warning in some cases (see testdata change for
uselessElvisRightIsNull.kt). However, this removes warning about
*unnecessary* elvis, i.e. this fixed introduces weak false-negatives, which
is acceptable for the moment.

#KT-20855 Fixed Target versions 1.2.30
#KT-20466 Fixed Target versions 1.2.30
#KT-21238 Fixed Target versions 1.2.30
This commit is contained in:
Dmitry Savvinov
2018-01-25 14:18:39 +03:00
parent 4c76dc7287
commit 4d951de616
12 changed files with 472 additions and 3 deletions
@@ -0,0 +1,85 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
// JSR305_GLOBAL_REPORT warn
// FILE: MyNotNull.java
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierNickname;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.PARAMETER})
@Nonnull
@TypeQualifierNickname
@Retention(RetentionPolicy.RUNTIME)
public @interface MyNotNull {}
// FILE: AnnotatedWithJsr.java
public class AnnotatedWithJsr {
@MyNotNull
public String getString() {
return null;
}
public void consumeString(@MyNotNull String s) { }
}
// FILE: AnnotatedWithJB.java
import org.jetbrains.annotations.NotNull;
public class AnnotatedWithJB {
public @NotNull String getString() {
return "hello";
}
public void consumeString(@NotNull String s) { }
}
// FILE: PlainJava.java
public class PlainJava {
public String getString() {
return null;
}
public void consumeString(String s) { }
}
// FILE: main.kt
val jsr: AnnotatedWithJsr = AnnotatedWithJsr()
val jsrNullable: AnnotatedWithJsr? = null
val jb: AnnotatedWithJB = AnnotatedWithJB()
val jbNullable: AnnotatedWithJB? = null
val platform: PlainJava = PlainJava()
val platformNullable: PlainJava? = null
object Elvis {
fun fromJava() {
val a = jsr.string ?: ""
val b = jsrNullable?.string ?: ""
val c = jb.string <!USELESS_ELVIS!>?: ""<!>
val d = jbNullable?.string ?: ""
val e = platform.string ?: ""
val f = platformNullable?.string ?: ""
}
fun toJava(nullableString: String?) {
val b = jsr.consumeString(nullableString ?: "")
val d = jsrNullable?.consumeString(nullableString ?: "")
val f = jb.consumeString(nullableString ?: "")
val h = jbNullable?.consumeString(nullableString ?: "")
val j = platform.consumeString(nullableString ?: "")
val l = platformNullable?.consumeString(nullableString ?: "")
}
}
@@ -0,0 +1,51 @@
package
public val jb: AnnotatedWithJB
public val jbNullable: AnnotatedWithJB? = null
public val jsr: AnnotatedWithJsr
public val jsrNullable: AnnotatedWithJsr? = null
public val platform: PlainJava
public val platformNullable: PlainJava? = null
public open class AnnotatedWithJB {
public constructor AnnotatedWithJB()
public open fun consumeString(/*0*/ @org.jetbrains.annotations.NotNull s: kotlin.String): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@org.jetbrains.annotations.NotNull public open fun getString(): kotlin.String
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class AnnotatedWithJsr {
public constructor AnnotatedWithJsr()
public open fun consumeString(/*0*/ @MyNotNull s: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyNotNull public open fun getString(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public object Elvis {
private constructor Elvis()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun fromJava(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun toJava(/*0*/ nullableString: kotlin.String?): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.VALUE_PARAMETER}) @javax.annotation.Nonnull @javax.annotation.meta.TypeQualifierNickname @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class MyNotNull : kotlin.Annotation {
public constructor MyNotNull()
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 open class PlainJava {
public constructor PlainJava()
public open fun consumeString(/*0*/ s: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun getString(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -28,7 +28,7 @@ fun test() {
foo(a)
val b = JJ.staticNN ?: null
foo(b)
val c = JJJ.staticNNN ?: <!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>
val c = JJJ.staticNNN ?: null
foo(c)
}
@@ -0,0 +1,96 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION
// JSR305_GLOBAL_REPORT warn
// FILE: MyNotNull.java
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierNickname;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.PARAMETER})
@Nonnull
@TypeQualifierNickname
@Retention(RetentionPolicy.RUNTIME)
public @interface MyNotNull {}
// FILE: AnnotatedWithJsr.java
public class AnnotatedWithJsr {
@MyNotNull
public String getString() {
return null;
}
public void consumeString(@MyNotNull String s) { }
}
// FILE: AnnotatedWithJB.java
import org.jetbrains.annotations.NotNull;
public class AnnotatedWithJB {
public @NotNull String getString() {
return "hello";
}
public void consumeString(@NotNull String s) { }
}
// FILE: PlainJava.java
public class PlainJava {
public String getString() {
return null;
}
public void consumeString(String s) { }
}
// FILE: main.kt
val jsr: AnnotatedWithJsr = AnnotatedWithJsr()
val jsrNullable: AnnotatedWithJsr? = null
val jb: AnnotatedWithJB = AnnotatedWithJB()
val jbNullable: AnnotatedWithJB? = null
val platform: PlainJava = PlainJava()
val platformNullable: PlainJava? = null
val a = jsr.string
val b = jsrNullable?.string
val c = jb.string
val d = jbNullable?.string
val e = platform.string
val f = platformNullable?.string
fun evlis() {
// JSR
val r1 = a ?: ""
val r2 = b ?: ""
// JB
val r3 = c <!USELESS_ELVIS!>?: ""<!>
val r4 = d ?: ""
// Platform
val r5 = e ?: ""
val r6 = f ?: ""
}
fun ifChecksAndSmartCasts() {
// JSR
val r1 = if (<!SENSELESS_COMPARISON, SENSELESS_COMPARISON!>a == null<!>) 42 else a.length
val r2 = if (b == null) 42 else <!DEBUG_INFO_SMARTCAST!>b<!>.length
// JB
val r3 = if (<!SENSELESS_COMPARISON!>c == null<!>) 42 else c.length
val r4 = if (d == null) 42 else <!DEBUG_INFO_SMARTCAST!>d<!>.length
// Platform
val r5 = if (e == null) 42 else e.length
val r6 = if (f == null) 42 else <!DEBUG_INFO_SMARTCAST!>f<!>.length
}
@@ -0,0 +1,50 @@
package
public val a: kotlin.String!
public val b: kotlin.String?
public val c: kotlin.String
public val d: kotlin.String?
public val e: kotlin.String!
public val f: kotlin.String?
public val jb: AnnotatedWithJB
public val jbNullable: AnnotatedWithJB? = null
public val jsr: AnnotatedWithJsr
public val jsrNullable: AnnotatedWithJsr? = null
public val platform: PlainJava
public val platformNullable: PlainJava? = null
public fun evlis(): kotlin.Unit
public fun ifChecksAndSmartCasts(): kotlin.Unit
public open class AnnotatedWithJB {
public constructor AnnotatedWithJB()
public open fun consumeString(/*0*/ @org.jetbrains.annotations.NotNull s: kotlin.String): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@org.jetbrains.annotations.NotNull public open fun getString(): kotlin.String
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class AnnotatedWithJsr {
public constructor AnnotatedWithJsr()
public open fun consumeString(/*0*/ @MyNotNull s: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyNotNull public open fun getString(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.VALUE_PARAMETER}) @javax.annotation.Nonnull @javax.annotation.meta.TypeQualifierNickname @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class MyNotNull : kotlin.Annotation {
public constructor MyNotNull()
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 open class PlainJava {
public constructor PlainJava()
public open fun consumeString(/*0*/ s: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun getString(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,72 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
// JSR305_GLOBAL_REPORT warn
// FILE: MyNotNull.java
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierNickname;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.PARAMETER})
@Nonnull
@TypeQualifierNickname
@Retention(RetentionPolicy.RUNTIME)
public @interface MyNotNull {}
// FILE: AnnotatedWithJsr.java
public class AnnotatedWithJsr {
@MyNotNull
public String getString() {
return null;
}
public void consumeString(@MyNotNull String s) { }
}
// FILE: AnnotatedWithJB.java
import org.jetbrains.annotations.NotNull;
public class AnnotatedWithJB {
public @NotNull String getString() {
return "hello";
}
public void consumeString(@NotNull String s) { }
}
// FILE: PlainJava.java
public class PlainJava {
public String getString() {
return null;
}
public void consumeString(String s) { }
}
// FILE: main.kt
val jsr: AnnotatedWithJsr = AnnotatedWithJsr()
val jsrNullable: AnnotatedWithJsr? = null
val jb: AnnotatedWithJB = AnnotatedWithJB()
val jbNullable: AnnotatedWithJB? = null
val platform: PlainJava = PlainJava()
val platformNullable: PlainJava? = null
fun safeCalls() {
val a = jsr.string<!UNNECESSARY_SAFE_CALL!>?.<!>length
val b = jsrNullable?.string?.length
val c = jb.string<!UNNECESSARY_SAFE_CALL!>?.<!>length
val d = jbNullable?.string?.length
val e = platform.string?.length
val f = platformNullable?.string?.length
}
@@ -0,0 +1,43 @@
package
public val jb: AnnotatedWithJB
public val jbNullable: AnnotatedWithJB? = null
public val jsr: AnnotatedWithJsr
public val jsrNullable: AnnotatedWithJsr? = null
public val platform: PlainJava
public val platformNullable: PlainJava? = null
public fun safeCalls(): kotlin.Unit
public open class AnnotatedWithJB {
public constructor AnnotatedWithJB()
public open fun consumeString(/*0*/ @org.jetbrains.annotations.NotNull s: kotlin.String): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@org.jetbrains.annotations.NotNull public open fun getString(): kotlin.String
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class AnnotatedWithJsr {
public constructor AnnotatedWithJsr()
public open fun consumeString(/*0*/ @MyNotNull s: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@MyNotNull public open fun getString(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.VALUE_PARAMETER}) @javax.annotation.Nonnull @javax.annotation.meta.TypeQualifierNickname @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class MyNotNull : kotlin.Annotation {
public constructor MyNotNull()
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 open class PlainJava {
public constructor PlainJava()
public open fun consumeString(/*0*/ s: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun getString(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -128,6 +128,18 @@ public class ForeignAnnotationsNoAnnotationInClasspathTestGenerated extends Abst
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("elvis.kt")
public void testElvis() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/elvis.kt");
doTest(fileName);
}
@TestMetadata("localInference.kt")
public void testLocalInference() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/localInference.kt");
doTest(fileName);
}
@TestMetadata("nullabilityGenerics.kt")
public void testNullabilityGenerics() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/nullabilityGenerics.kt");
@@ -140,6 +152,12 @@ public class ForeignAnnotationsNoAnnotationInClasspathTestGenerated extends Abst
doTest(fileName);
}
@TestMetadata("safeCalls.kt")
public void testSafeCalls() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/safeCalls.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/simple.kt");
@@ -128,6 +128,18 @@ public class ForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTestGe
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("elvis.kt")
public void testElvis() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/elvis.kt");
doTest(fileName);
}
@TestMetadata("localInference.kt")
public void testLocalInference() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/localInference.kt");
doTest(fileName);
}
@TestMetadata("nullabilityGenerics.kt")
public void testNullabilityGenerics() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/nullabilityGenerics.kt");
@@ -140,6 +152,12 @@ public class ForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTestGe
doTest(fileName);
}
@TestMetadata("safeCalls.kt")
public void testSafeCalls() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/safeCalls.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/simple.kt");
@@ -128,6 +128,18 @@ public class ForeignAnnotationsTestGenerated extends AbstractForeignAnnotationsT
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("elvis.kt")
public void testElvis() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/elvis.kt");
doTest(fileName);
}
@TestMetadata("localInference.kt")
public void testLocalInference() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/localInference.kt");
doTest(fileName);
}
@TestMetadata("nullabilityGenerics.kt")
public void testNullabilityGenerics() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/nullabilityGenerics.kt");
@@ -140,6 +152,12 @@ public class ForeignAnnotationsTestGenerated extends AbstractForeignAnnotationsT
doTest(fileName);
}
@TestMetadata("safeCalls.kt")
public void testSafeCalls() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/safeCalls.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/simple.kt");
@@ -128,6 +128,18 @@ public class JavacForeignAnnotationsTestGenerated extends AbstractJavacForeignAn
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("elvis.kt")
public void testElvis() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/elvis.kt");
doTest(fileName);
}
@TestMetadata("localInference.kt")
public void testLocalInference() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/localInference.kt");
doTest(fileName);
}
@TestMetadata("nullabilityGenerics.kt")
public void testNullabilityGenerics() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/nullabilityGenerics.kt");
@@ -140,6 +152,12 @@ public class JavacForeignAnnotationsTestGenerated extends AbstractJavacForeignAn
doTest(fileName);
}
@TestMetadata("safeCalls.kt")
public void testSafeCalls() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/safeCalls.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/simple.kt");
@@ -38,7 +38,7 @@ class SimpleTypeWithEnhancement(
= origin.replaceAnnotations(newAnnotations).wrapEnhancement(enhancement) as SimpleType
override fun makeNullableAsSpecified(newNullability: Boolean): SimpleType
= origin.makeNullableAsSpecified(newNullability).wrapEnhancement(enhancement) as SimpleType
= origin.makeNullableAsSpecified(newNullability).wrapEnhancement(enhancement.unwrap().makeNullableAsSpecified(newNullability)) as SimpleType
}
class FlexibleTypeWithEnhancement(
@@ -51,7 +51,7 @@ class FlexibleTypeWithEnhancement(
= origin.replaceAnnotations(newAnnotations).wrapEnhancement(enhancement)
override fun makeNullableAsSpecified(newNullability: Boolean): UnwrappedType
= origin.makeNullableAsSpecified(newNullability).wrapEnhancement(enhancement)
= origin.makeNullableAsSpecified(newNullability).wrapEnhancement(enhancement.unwrap().makeNullableAsSpecified(newNullability))
override fun render(renderer: DescriptorRenderer, options: DescriptorRendererOptions): String
= origin.render(renderer, options)