Kapt3: Ignore declarations with illegal Java identifiers (KT-16153)

This commit is contained in:
Yan Zhulanow
2017-02-03 20:52:26 +03:00
parent 7296d9cb7c
commit 08b98f7133
5 changed files with 123 additions and 35 deletions
@@ -172,7 +172,7 @@ class ClassFileToSourceStubConverter(
return null return null
} }
val simpleName = getClassName(clazz, descriptor, isDefaultImpls, packageFqName) val simpleName = getValidIdentifierName(getClassName(clazz, descriptor, isDefaultImpls, packageFqName)) ?: return null
val interfaces = mapJList(clazz.interfaces) { val interfaces = mapJList(clazz.interfaces) {
if (isAnnotation && it == "java/lang/annotation/Annotation") return@mapJList null if (isAnnotation && it == "java/lang/annotation/Annotation") return@mapJList null
@@ -245,7 +245,7 @@ class ClassFileToSourceStubConverter(
return treeMaker.ClassDef( return treeMaker.ClassDef(
modifiers, modifiers,
treeMaker.name(getNonKeywordName(simpleName)), treeMaker.name(simpleName),
genericType.typeParameters, genericType.typeParameters,
if (hasSuperClass) genericType.superClass else null, if (hasSuperClass) genericType.superClass else null,
genericType.interfaces, genericType.interfaces,
@@ -279,7 +279,7 @@ class ClassFileToSourceStubConverter(
val descriptor = kaptContext.origins[field]?.descriptor val descriptor = kaptContext.origins[field]?.descriptor
val modifiers = convertModifiers(field.access, ElementKind.FIELD, packageFqName, field.visibleAnnotations, field.invisibleAnnotations) val modifiers = convertModifiers(field.access, ElementKind.FIELD, packageFqName, field.visibleAnnotations, field.invisibleAnnotations)
val name = treeMaker.name(getNonKeywordName(field.name)) val name = getValidIdentifierName(field.name) ?: return null
val type = Type.getType(field.desc) val type = Type.getType(field.desc)
// Enum type must be an identifier (Javac requirement) // Enum type must be an identifier (Javac requirement)
@@ -298,7 +298,7 @@ class ClassFileToSourceStubConverter(
?: convertValueOfPrimitiveTypeOrString(value) ?: convertValueOfPrimitiveTypeOrString(value)
?: if (isFinal(field.access)) convertLiteralExpression(getDefaultValue(type)) else null ?: if (isFinal(field.access)) convertLiteralExpression(getDefaultValue(type)) else null
return treeMaker.VarDef(modifiers, name, typeExpression, initializer) return treeMaker.VarDef(modifiers, treeMaker.name(name), typeExpression, initializer)
} }
private fun convertMethod(method: MethodNode, containingClass: ClassNode, packageFqName: String): JCMethodDecl? { private fun convertMethod(method: MethodNode, containingClass: ClassNode, packageFqName: String): JCMethodDecl? {
@@ -318,7 +318,7 @@ class ClassFileToSourceStubConverter(
} }
val isConstructor = method.name == "<init>" val isConstructor = method.name == "<init>"
val name = treeMaker.name(getNonKeywordName(method.name)) val name = getValidIdentifierName(method.name, canBeConstructor = true) ?: return null
val modifiers = convertModifiers( val modifiers = convertModifiers(
if (containingClass.isEnum() && isConstructor) if (containingClass.isEnum() && isConstructor)
@@ -344,7 +344,7 @@ class ClassFileToSourceStubConverter(
info.visibleAnnotations, info.visibleAnnotations,
info.invisibleAnnotations) info.invisibleAnnotations)
val name = treeMaker.name(getNonKeywordName(info.name)) val name = treeMaker.name(getValidIdentifierName(info.name) ?: "p${index}_" + info.name.hashCode())
val type = treeMaker.Type(info.type) val type = treeMaker.Type(info.type)
treeMaker.VarDef(modifiers, name, type, null) treeMaker.VarDef(modifiers, name, type, null)
} }
@@ -388,7 +388,7 @@ class ClassFileToSourceStubConverter(
} }
return treeMaker.MethodDef( return treeMaker.MethodDef(
modifiers, name, returnType, genericSignature.typeParameters, modifiers, treeMaker.name(name), returnType, genericSignature.typeParameters,
genericSignature.parameterTypes, genericSignature.exceptionTypes, genericSignature.parameterTypes, genericSignature.exceptionTypes,
body, defaultValue) body, defaultValue)
} }
@@ -452,9 +452,21 @@ class ClassFileToSourceStubConverter(
return ifNonError() return ifNonError()
} }
private fun getNonKeywordName(name: String): String { fun getValidIdentifierName(name: String, canBeConstructor: Boolean = false): String? {
if (canBeConstructor && name == "<init>") {
return name
}
// In theory, this could lead to member/parameter name clashes, though it's supposed to be extremely rare. // In theory, this could lead to member/parameter name clashes, though it's supposed to be extremely rare.
if (name in JAVA_KEYWORDS) return '_' + name + '_' if (name in JAVA_KEYWORDS) return '_' + name + '_'
if (name.isEmpty()
|| !Character.isJavaIdentifierStart(name[0])
|| name.drop(1).any { !Character.isJavaIdentifierPart(it) }
) {
return null
}
return name return name
} }
@@ -532,7 +544,8 @@ class ClassFileToSourceStubConverter(
val useSimpleName = '.' in fqName && fqName.substringBeforeLast('.', "") == packageFqName val useSimpleName = '.' in fqName && fqName.substringBeforeLast('.', "") == packageFqName
val name = if (useSimpleName) treeMaker.FqName(fqName.substring(packageFqName!!.length + 1)) else treeMaker.Type(annotationType) val name = if (useSimpleName) treeMaker.FqName(fqName.substring(packageFqName!!.length + 1)) else treeMaker.Type(annotationType)
val values = mapPairedValuesJList<JCExpression>(annotation.values) { key, value -> val values = mapPairedValuesJList<JCExpression>(annotation.values) { key, value ->
treeMaker.Assign(treeMaker.SimpleName(key), convertLiteralExpression(value)) val name = getValidIdentifierName(key) ?: return@mapPairedValuesJList null
treeMaker.Assign(treeMaker.SimpleName(name), convertLiteralExpression(value))
} }
return treeMaker.Annotation(name, values) return treeMaker.Annotation(name, values)
} }
@@ -564,7 +577,7 @@ class ClassFileToSourceStubConverter(
is Array<*> -> { // Two-element String array for enumerations ([desc, fieldName]) is Array<*> -> { // Two-element String array for enumerations ([desc, fieldName])
assert(value.size == 2) assert(value.size == 2)
val enumType = Type.getType(value[0] as String) val enumType = Type.getType(value[0] as String)
val valueName = value[1] as String val valueName = getValidIdentifierName(value[1] as String) ?: "InvalidFieldName"
treeMaker.Select(treeMaker.Type(enumType), treeMaker.name(valueName)) treeMaker.Select(treeMaker.Type(enumType), treeMaker.name(valueName))
} }
is List<*> -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value) { convertLiteralExpression(it) }) is List<*> -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value) { convertLiteralExpression(it) })
@@ -222,6 +222,12 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi
doTest(fileName); doTest(fileName);
} }
@TestMetadata("strangeIdentifiers.kt")
public void testStrangeIdentifiers() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/strangeIdentifiers.kt");
doTest(fileName);
}
@TestMetadata("strangeNames.kt") @TestMetadata("strangeNames.kt")
public void testStrangeNames() throws Exception { public void testStrangeNames() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/strangeNames.kt"); String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/strangeNames.kt");
+38
View File
@@ -0,0 +1,38 @@
class `:)` {
lateinit val f: String
}
// Commented declarations won't compile with the current Kotlin
class Test {
class `(^_^)`
lateinit val simpleName: String
lateinit val `strange name`: String
// lateinit val strangeType: List<`!A@`>
fun simpleFun() {}
@Anno(name = "Woofwoof", size = StrangeEnum.`60x60`, `A B` = "S")
fun simpleFun2(a: String, b: String) {}
fun `strange!Fun`() {}
// fun strangeFun2(a: String, b: `A()B()`) {}
// fun strangeFun3(a: String, b: `A B`) {}
fun strangeFun4(a: String, `A()B()`: String) {}
// fun strangeFun5(a: `A B`.C) {}
}
enum class StrangeEnum(val size: String) {
`60x60`("60x60"),
`70x70`("70x70"),
`80x80`("80x80"),
InvalidFieldName("0x0") // Workaround to pass javac analysis
}
annotation class Anno(val size: StrangeEnum, val name: String, val `A B`: String)
class `!A@`
class `A()B()`
class `A B` {
class C
}
+56
View File
@@ -0,0 +1,56 @@
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
public abstract @interface Anno {
public abstract StrangeEnum size();
public abstract java.lang.String name();
}
////////////////////
public enum StrangeEnum {
/*public static final*/ InvalidFieldName /* = new InvalidFieldName(null) */;
@org.jetbrains.annotations.NotNull()
private final java.lang.String size = null;
@org.jetbrains.annotations.NotNull()
public final java.lang.String getSize() {
return null;
}
StrangeEnum(@org.jetbrains.annotations.NotNull()
java.lang.String size) {
}
}
////////////////////
public final class Test {
@org.jetbrains.annotations.NotNull()
public java.lang.String simpleName;
@org.jetbrains.annotations.NotNull()
public final java.lang.String getSimpleName() {
return null;
}
public final void simpleFun() {
}
@Anno(name = "Woofwoof", size = StrangeEnum.InvalidFieldName)
public final void simpleFun2(@org.jetbrains.annotations.NotNull()
java.lang.String a, @org.jetbrains.annotations.NotNull()
java.lang.String b) {
}
public final void strangeFun4(@org.jetbrains.annotations.NotNull()
java.lang.String a, @org.jetbrains.annotations.NotNull()
java.lang.String p1_1899121793) {
}
public Test() {
super();
}
}
-25
View File
@@ -1,26 +1 @@
public final class My $ name {
@org.jetbrains.annotations.NotNull()
private final java.lang.String (@\u2022@) = "";
@org.jetbrains.annotations.NotNull()
private final java.lang.String \u041a\u043e\u0442\u043b\u0438\u043d-\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 = "";
public final void (^_^)(int )))))) {
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String get(@\u2022@)() {
return null;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String get\u041a\u043e\u0442\u043b\u0438\u043d-\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440() {
return null;
}
public final void \u3053\u3000\u3068\u3000\u308a\u3000\u3093\uff01() {
}
public My $ name() {
super();
}
}