Support reflection tests on Android
This commit is contained in:
+61
-17
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.codegen.CodegenTestCase
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
|
||||
@@ -31,8 +30,10 @@ private val packagePattern = Pattern.compile("(?m)^\\s*package[ |\t]+([\\w|\\.]*
|
||||
|
||||
private val importPattern = Pattern.compile("import[ |\t]([\\w|]*\\.)")
|
||||
|
||||
private data class OldPackageAndNew(val oldFqName: FqName, val newFqName: FqName)
|
||||
|
||||
internal fun patchFiles(
|
||||
file: File,
|
||||
testFile: File,
|
||||
testFiles: List<CodegenTestCase.TestFile>,
|
||||
filesHolder: CodegenTestsOnAndroidGenerator.FilesWriter
|
||||
): FqName? {
|
||||
@@ -43,11 +44,11 @@ internal fun patchFiles(
|
||||
val ktFiles = testFiles.filter { it.name.endsWith(".kt") }
|
||||
if (ktFiles.isEmpty()) return null
|
||||
|
||||
val newPackagePrefix = file.path.replace("\\\\|-|\\.|/".toRegex(), "_")
|
||||
val newPackagePrefix = testFile.path.replace("\\\\|-|\\.|/".toRegex(), "_")
|
||||
val oldPackage = Ref<FqName>()
|
||||
val isSingle = testFiles.size == 1
|
||||
val resultFiles = testFiles.map {
|
||||
val fileName = if (isSingle) it.name else file.name.substringBeforeLast(".kt") + "/" + it.name
|
||||
val fileName = if (isSingle) it.name else testFile.name.substringBeforeLast(".kt") + "/" + it.name
|
||||
TestClassInfo(
|
||||
fileName,
|
||||
changePackage(newPackagePrefix, it.content, oldPackage),
|
||||
@@ -55,21 +56,51 @@ internal fun patchFiles(
|
||||
getGeneratedClassName(File(fileName), it.content, newPackagePrefix, oldPackage.get())
|
||||
)
|
||||
}
|
||||
val packages =
|
||||
resultFiles.map { OldPackageAndNew(it.oldPackage, it.newClassId.parent()) }.sortedByDescending { it.oldFqName.asString().length }
|
||||
|
||||
/*replace all Class.forName*/
|
||||
resultFiles.forEach {
|
||||
file ->
|
||||
file.content = resultFiles.fold(file.content) { r, param ->
|
||||
patchClassForName(param.newClassId, param.oldPackage, r)
|
||||
//If files contain any val or var declaration with same name as any package name
|
||||
// then use old conservative renaming scheme, otherwise use aggressive one
|
||||
// with old package renaming to new one (except some cases for default package)
|
||||
// Example for conservative switch:
|
||||
// package foo
|
||||
// ...
|
||||
// val foo = ....
|
||||
// class A(val foo ...)
|
||||
// fun foo()= { var foo ...}
|
||||
val conservativeRenameScheme = resultFiles.any { file ->
|
||||
packages.any {
|
||||
if (it.oldFqName.isRoot || !it.oldFqName.parent().isRoot) false
|
||||
else file.content.contains("(val|var)\\s+${it.oldFqName.asString()}[^A-Za-z0-9_.]".toRegex())
|
||||
}
|
||||
}
|
||||
|
||||
/*patch imports and self imports*/
|
||||
resultFiles.forEach {
|
||||
file ->
|
||||
if (!conservativeRenameScheme) {
|
||||
/*replace all packages*/
|
||||
resultFiles.forEach { file ->
|
||||
file.content = packages.fold(file.content) { r, param ->
|
||||
patchPackages(param.newFqName, param.oldFqName, r)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//patch imports
|
||||
resultFiles.forEach { file ->
|
||||
file.content = packages.fold(file.content) { r, param ->
|
||||
r.patchImports(param.oldFqName, param.newFqName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*replace all Class.forName*/
|
||||
resultFiles.forEach { file ->
|
||||
file.content = resultFiles.fold(file.content) { r, param ->
|
||||
r.patchImports(param.oldPackage, param.newPackage)
|
||||
}.patchSelfImports(file.newPackage)
|
||||
patchClassForName(param.newClassId, param.oldPackage, r, conservativeRenameScheme)
|
||||
}
|
||||
}
|
||||
|
||||
//patch self imports
|
||||
resultFiles.forEach { file ->
|
||||
file.content = file.content.patchSelfImports(file.newPackage)
|
||||
}
|
||||
|
||||
resultFiles.forEach { resultFile ->
|
||||
@@ -80,7 +111,7 @@ internal fun patchFiles(
|
||||
|
||||
val boxFiles = resultFiles.filter { hasBoxMethod(it.content) }
|
||||
if (boxFiles.size != 1) {
|
||||
println("Several box methods in $file")
|
||||
println("Several box methods in $testFile")
|
||||
}
|
||||
return boxFiles.last().newClassId
|
||||
}
|
||||
@@ -132,8 +163,21 @@ private fun getGeneratedClassName(file: File, text: String, newPackagePrefix: St
|
||||
return PackagePartClassUtils.getPackagePartFqName(packageFqName, file.name)
|
||||
}
|
||||
|
||||
private fun patchClassForName(className: FqName, oldPackage: FqName, text: String): String {
|
||||
return text.replace(("Class\\.forName\\(\"" + oldPackage.child(className.shortName()).asString() + "\"\\)").toRegex(), "Class.forName(\"" + className.asString() + "\")")
|
||||
private fun patchClassForName(className: FqName, oldPackage: FqName, text: String, conservativeRenameSchemeheme: Boolean): String {
|
||||
if (!conservativeRenameSchemeheme && !oldPackage.isRoot) return text
|
||||
return text.replace(
|
||||
("Class\\.forName\\(\"" + oldPackage.child(className.shortName()).asString()).toRegex(),
|
||||
"Class.forName(\"" + className.asString()
|
||||
)
|
||||
}
|
||||
|
||||
private fun patchPackages(newPackage: FqName, oldPackage: FqName, text: String): String {
|
||||
if (oldPackage.isRoot) return text
|
||||
|
||||
val regexp = "([^A-Za-z0-9.])" + (oldPackage.asString() + ".").replace(".", "\\.")
|
||||
return text.replace(
|
||||
regexp.toRegex(), "$1" + newPackage.asString() + "."
|
||||
)
|
||||
}
|
||||
|
||||
private fun String.patchImports(oldPackage: FqName, newPackage: FqName): String {
|
||||
|
||||
@@ -33,62 +33,25 @@ public class SpecialFiles {
|
||||
private static void fillExcludedFiles() {
|
||||
// Reflection
|
||||
excludedFiles.add("enclosing");
|
||||
excludedFiles.add("noReflectAtRuntime");
|
||||
excludedFiles.add("methodsFromAny");
|
||||
excludedFiles.add("genericProperty.kt");
|
||||
excludedFiles.add("kt3238.kt");
|
||||
excludedFiles.add("kt1482_2279.kt");
|
||||
excludedFiles.add("extensionMethod.kt");
|
||||
excludedFiles.add("functionNtoStringNoReflect.kt");
|
||||
excludedFiles.add("innerGeneric.kt");
|
||||
excludedFiles.add("simpleCreateType.kt");
|
||||
excludedFiles.add("equalsHashCodeToString.kt");
|
||||
excludedFiles.add("arrayOfKClasses.kt");
|
||||
excludedFiles.add("enumKClassAnnotation.kt");
|
||||
excludedFiles.add("primitivesAndArrays.kt");
|
||||
excludedFiles.add("getDelegateWithoutReflection.kt");
|
||||
excludedFiles.add("parameterAnnotationInDefaultImpls.kt");
|
||||
excludedFiles.add("kt17091.kt");
|
||||
excludedFiles.add("kt17091_2.kt");
|
||||
excludedFiles.add("kt17091_3.kt");
|
||||
excludedFiles.add("kt22906.kt");
|
||||
excludedFiles.add("kt10259.kt");
|
||||
excludedFiles.add("simpleClassLiteral.kt");
|
||||
|
||||
// Reflection is used to check full class name
|
||||
excludedFiles.add("native");
|
||||
//UnsatisfiedLinkError
|
||||
excludedFiles.add("nativePropertyAccessors.kt");
|
||||
excludedFiles.add("topLevel.kt");
|
||||
|
||||
//Test with no reflection at runtime
|
||||
excludedFiles.add("noReflectAtRuntime");
|
||||
excludedFiles.add("functionNtoStringNoReflect.kt");
|
||||
excludedFiles.add("getDelegateWithoutReflection.kt");
|
||||
|
||||
// "IOOBE: Invalid index 4, size is 4" for java.lang.reflect.ParameterizedType on Android
|
||||
excludedFiles.add("innerGenericTypeArgument.kt");
|
||||
|
||||
// Cannot change package name
|
||||
excludedFiles.add("nestedInPackage.kt");
|
||||
excludedFiles.add("packageQualifiedMethod.kt");
|
||||
excludedFiles.add("classObjectToString.kt");
|
||||
excludedFiles.add("assertionStackTrace.kt");
|
||||
excludedFiles.add("anonymousObjectReifiedSupertype.kt");
|
||||
excludedFiles.add("innerAnonymousObject.kt");
|
||||
excludedFiles.add("nestedReifiedSignature.kt");
|
||||
excludedFiles.add("recursiveInnerAnonymousObject.kt");
|
||||
excludedFiles.add("approximateCapturedTypes.kt");
|
||||
excludedFiles.add("classForEnumEntry.kt");
|
||||
excludedFiles.add("kt10143.kt");
|
||||
excludedFiles.add("internalTopLevelOtherPackage.kt");
|
||||
excludedFiles.add("noPrivateDelegation.kt");
|
||||
excludedFiles.add("platformTypeAssertionStackTrace.kt");
|
||||
excludedFiles.add("packages.kt");
|
||||
excludedFiles.add("kt10259.kt");
|
||||
excludedFiles.add("kt11081.kt");
|
||||
excludedFiles.add("kt6990.kt");
|
||||
excludedFiles.add("mainInFiles.kt");
|
||||
excludedFiles.add("noClassForSimpleEnum.kt");
|
||||
excludedFiles.add("simpleClassLiteral.kt");
|
||||
excludedFiles.add("jvmName.kt");
|
||||
excludedFiles.add("qualifiedName.kt");
|
||||
excludedFiles.add("topLevelProperty.kt");
|
||||
excludedFiles.add("typeParameters.kt");
|
||||
excludedFiles.add("kt13133.kt");
|
||||
excludedFiles.add("genericOverriddenFunction.kt");
|
||||
excludedFiles.add("genericOverriddenProperty.kt");
|
||||
excludedFiles.add("genericProperty.kt");
|
||||
|
||||
// StackOverflow with StringBuilder (escape())
|
||||
excludedFiles.add("kt684.kt");
|
||||
@@ -96,18 +59,6 @@ public class SpecialFiles {
|
||||
// Wrong enclosing info or signature after package renaming
|
||||
excludedFiles.add("enclosingInfo");
|
||||
excludedFiles.add("signature");
|
||||
excludedFiles.add("genericBackingFieldSignature.kt");
|
||||
excludedFiles.add("genericMethodSignature.kt");
|
||||
excludedFiles.add("kt11121.kt");
|
||||
excludedFiles.add("kt5112.kt");
|
||||
|
||||
// Different format of inner signature on Android and JVM
|
||||
excludedFiles.add("signatureOfDeepGenericInner.kt");
|
||||
excludedFiles.add("signatureOfDeepInner.kt");
|
||||
excludedFiles.add("signatureOfDeepInnerLastGeneric.kt");
|
||||
excludedFiles.add("signatureOfGenericInnerGenericOuter.kt");
|
||||
excludedFiles.add("signatureOfGenericInnerSimpleOuter.kt");
|
||||
excludedFiles.add("signatureOfSimpleInnerSimpleOuter.kt");
|
||||
|
||||
// Some classes are not visible on android
|
||||
excludedFiles.add("classpath.kt");
|
||||
@@ -120,8 +71,6 @@ public class SpecialFiles {
|
||||
|
||||
// Additional nested class in 'Thread' class on Android
|
||||
excludedFiles.add("nestedClasses.kt");
|
||||
// No 'modifiers' field in 'java.lang.reflect.Field' class
|
||||
excludedFiles.add("kt12200Const.kt");
|
||||
|
||||
// KT-8120
|
||||
excludedFiles.add("closureOfInnerLocalClass.kt");
|
||||
|
||||
Reference in New Issue
Block a user