Infer lateinit-exposed field effective visibility from its setter visibility.

This commit is contained in:
Ilya Gorbunov
2016-03-23 23:00:40 +03:00
parent f2cb5edf1a
commit 0d12d60e8a
3 changed files with 27 additions and 7 deletions
@@ -37,7 +37,10 @@ interface MemberBinarySignature {
fun isEffectivelyPublic(classAccess: AccessFlags, classVisibility: ClassVisibility?)
= access.isPublic && !(access.isProtected && classAccess.isFinal)
&& (classVisibility?.members?.get(MemberSignature(name, desc))?.isPublic(isInlineExposed) ?: true)
&& (findMemberVisibility(classVisibility)?.isPublic(isInlineExposed) ?: true)
fun findMemberVisibility(classVisibility: ClassVisibility?)
= classVisibility?.members?.get(MemberSignature(name, desc))
val signature: String
}
@@ -65,9 +68,15 @@ data class FieldBinarySignature(
override val signature: String
get() = "${access.getModifierString()} field $name $desc"
override fun isEffectivelyPublic(classAccess: AccessFlags, classVisibility: ClassVisibility?)
= super.isEffectivelyPublic(classAccess, classVisibility)
// TODO: lateinit exposed field
override fun findMemberVisibility(classVisibility: ClassVisibility?): MemberVisibility? {
val fieldVisibility = super.findMemberVisibility(classVisibility) ?: return null
// good case for 'satisfying': fieldVisibility.satisfying { it.isLateInit() }?.let { classVisibility?.findSetterForProperty(it) }
if (fieldVisibility.isLateInit()) {
classVisibility?.findSetterForProperty(fieldVisibility)?.let { return it }
}
return fieldVisibility
}
}
@@ -5,13 +5,24 @@ import com.google.gson.stream.JsonReader
import java.io.File
data class ClassVisibility(val name: String, val visibility: String?, val members: Map<MemberSignature, MemberVisibility>)
data class MemberVisibility(val member: MemberSignature, val visibility: String?)
data class MemberVisibility(val member: MemberSignature, val declaration: String?, val visibility: String?)
data class MemberSignature(val name: String, val desc: String)
private fun isPublic(visibility: String?, isInlineExposed: Boolean) = visibility == null || visibility == "public" || visibility == "protected" || (isInlineExposed && visibility == "internal")
fun ClassVisibility.isPublic(isInlineExposed: Boolean) = isPublic(visibility, isInlineExposed)
fun MemberVisibility.isPublic(isInlineExposed: Boolean) = isPublic(visibility, isInlineExposed)
fun MemberVisibility.isLateInit() = declaration != null && "lateinit var " in declaration
private val varValPrefix = Regex("va[lr]\\s+")
fun ClassVisibility.findSetterForProperty(property: MemberVisibility): MemberVisibility? {
// ad-hoc solution:
val declaration = property.declaration ?: return null
val match = varValPrefix.find(declaration) ?: return null
val name = declaration.substring(match.range.endInclusive + 1).substringBefore(':')
val setterName = "<set-$name>"
return members.values.find { it.declaration?.contains(setterName) ?: false }
}
fun readKotlinVisibilities(declarationFile: File): Map<String, ClassVisibility> {
val result = mutableListOf<ClassVisibility>()
@@ -27,8 +38,9 @@ fun readKotlinVisibilities(declarationFile: File): Map<String, ClassVisibility>
with(it.asJsonObject) {
val name = getAsJsonPrimitive("name").asString
val desc = getAsJsonPrimitive("desc").asString
val declaration = getAsJsonPrimitive("declaration")?.asString
val visibility = getAsJsonPrimitive("visibility")?.asString
MemberVisibility(MemberSignature(name, desc), visibility)
MemberVisibility(MemberSignature(name, desc), declaration, visibility)
}
}
ClassVisibility(name, visibility, members.associateByTo(hashMapOf()) { it.member })
@@ -1,5 +1,4 @@
public final class cases/special/ClassWithLateInitMembers
public field publicLateInitWithInternalSet Ljava/lang/String;
public final fun getPublicLateInitWithInternalSet ()Ljava/lang/String;
------------------