Skip to content

Commit 08b98f7

Browse files
committed
Kapt3: Ignore declarations with illegal Java identifiers (KT-16153)
1 parent 7296d9c commit 08b98f7

File tree

5 files changed

+123
-35
lines changed

5 files changed

+123
-35
lines changed

plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ class ClassFileToSourceStubConverter(
172172
return null
173173
}
174174

175-
val simpleName = getClassName(clazz, descriptor, isDefaultImpls, packageFqName)
175+
val simpleName = getValidIdentifierName(getClassName(clazz, descriptor, isDefaultImpls, packageFqName)) ?: return null
176176

177177
val interfaces = mapJList(clazz.interfaces) {
178178
if (isAnnotation && it == "java/lang/annotation/Annotation") return@mapJList null
@@ -245,7 +245,7 @@ class ClassFileToSourceStubConverter(
245245

246246
return treeMaker.ClassDef(
247247
modifiers,
248-
treeMaker.name(getNonKeywordName(simpleName)),
248+
treeMaker.name(simpleName),
249249
genericType.typeParameters,
250250
if (hasSuperClass) genericType.superClass else null,
251251
genericType.interfaces,
@@ -279,7 +279,7 @@ class ClassFileToSourceStubConverter(
279279
val descriptor = kaptContext.origins[field]?.descriptor
280280

281281
val modifiers = convertModifiers(field.access, ElementKind.FIELD, packageFqName, field.visibleAnnotations, field.invisibleAnnotations)
282-
val name = treeMaker.name(getNonKeywordName(field.name))
282+
val name = getValidIdentifierName(field.name) ?: return null
283283
val type = Type.getType(field.desc)
284284

285285
// Enum type must be an identifier (Javac requirement)
@@ -298,7 +298,7 @@ class ClassFileToSourceStubConverter(
298298
?: convertValueOfPrimitiveTypeOrString(value)
299299
?: if (isFinal(field.access)) convertLiteralExpression(getDefaultValue(type)) else null
300300

301-
return treeMaker.VarDef(modifiers, name, typeExpression, initializer)
301+
return treeMaker.VarDef(modifiers, treeMaker.name(name), typeExpression, initializer)
302302
}
303303

304304
private fun convertMethod(method: MethodNode, containingClass: ClassNode, packageFqName: String): JCMethodDecl? {
@@ -318,7 +318,7 @@ class ClassFileToSourceStubConverter(
318318
}
319319

320320
val isConstructor = method.name == "<init>"
321-
val name = treeMaker.name(getNonKeywordName(method.name))
321+
val name = getValidIdentifierName(method.name, canBeConstructor = true) ?: return null
322322

323323
val modifiers = convertModifiers(
324324
if (containingClass.isEnum() && isConstructor)
@@ -344,7 +344,7 @@ class ClassFileToSourceStubConverter(
344344
info.visibleAnnotations,
345345
info.invisibleAnnotations)
346346

347-
val name = treeMaker.name(getNonKeywordName(info.name))
347+
val name = treeMaker.name(getValidIdentifierName(info.name) ?: "p${index}_" + info.name.hashCode())
348348
val type = treeMaker.Type(info.type)
349349
treeMaker.VarDef(modifiers, name, type, null)
350350
}
@@ -388,7 +388,7 @@ class ClassFileToSourceStubConverter(
388388
}
389389

390390
return treeMaker.MethodDef(
391-
modifiers, name, returnType, genericSignature.typeParameters,
391+
modifiers, treeMaker.name(name), returnType, genericSignature.typeParameters,
392392
genericSignature.parameterTypes, genericSignature.exceptionTypes,
393393
body, defaultValue)
394394
}
@@ -452,9 +452,21 @@ class ClassFileToSourceStubConverter(
452452
return ifNonError()
453453
}
454454

455-
private fun getNonKeywordName(name: String): String {
455+
fun getValidIdentifierName(name: String, canBeConstructor: Boolean = false): String? {
456+
if (canBeConstructor && name == "<init>") {
457+
return name
458+
}
459+
456460
// In theory, this could lead to member/parameter name clashes, though it's supposed to be extremely rare.
457461
if (name in JAVA_KEYWORDS) return '_' + name + '_'
462+
463+
if (name.isEmpty()
464+
|| !Character.isJavaIdentifierStart(name[0])
465+
|| name.drop(1).any { !Character.isJavaIdentifierPart(it) }
466+
) {
467+
return null
468+
}
469+
458470
return name
459471
}
460472

@@ -532,7 +544,8 @@ class ClassFileToSourceStubConverter(
532544
val useSimpleName = '.' in fqName && fqName.substringBeforeLast('.', "") == packageFqName
533545
val name = if (useSimpleName) treeMaker.FqName(fqName.substring(packageFqName!!.length + 1)) else treeMaker.Type(annotationType)
534546
val values = mapPairedValuesJList<JCExpression>(annotation.values) { key, value ->
535-
treeMaker.Assign(treeMaker.SimpleName(key), convertLiteralExpression(value))
547+
val name = getValidIdentifierName(key) ?: return@mapPairedValuesJList null
548+
treeMaker.Assign(treeMaker.SimpleName(name), convertLiteralExpression(value))
536549
}
537550
return treeMaker.Annotation(name, values)
538551
}
@@ -564,7 +577,7 @@ class ClassFileToSourceStubConverter(
564577
is Array<*> -> { // Two-element String array for enumerations ([desc, fieldName])
565578
assert(value.size == 2)
566579
val enumType = Type.getType(value[0] as String)
567-
val valueName = value[1] as String
580+
val valueName = getValidIdentifierName(value[1] as String) ?: "InvalidFieldName"
568581
treeMaker.Select(treeMaker.Type(enumType), treeMaker.name(valueName))
569582
}
570583
is List<*> -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value) { convertLiteralExpression(it) })

plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,12 @@ public void testSeveralPackageParts() throws Exception {
222222
doTest(fileName);
223223
}
224224

225+
@TestMetadata("strangeIdentifiers.kt")
226+
public void testStrangeIdentifiers() throws Exception {
227+
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/strangeIdentifiers.kt");
228+
doTest(fileName);
229+
}
230+
225231
@TestMetadata("strangeNames.kt")
226232
public void testStrangeNames() throws Exception {
227233
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/strangeNames.kt");
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
class `:)` {
2+
lateinit val f: String
3+
}
4+
5+
// Commented declarations won't compile with the current Kotlin
6+
class Test {
7+
class `(^_^)`
8+
9+
lateinit val simpleName: String
10+
lateinit val `strange name`: String
11+
// lateinit val strangeType: List<`!A@`>
12+
13+
fun simpleFun() {}
14+
15+
@Anno(name = "Woofwoof", size = StrangeEnum.`60x60`, `A B` = "S")
16+
fun simpleFun2(a: String, b: String) {}
17+
18+
fun `strange!Fun`() {}
19+
// fun strangeFun2(a: String, b: `A()B()`) {}
20+
// fun strangeFun3(a: String, b: `A B`) {}
21+
fun strangeFun4(a: String, `A()B()`: String) {}
22+
// fun strangeFun5(a: `A B`.C) {}
23+
}
24+
25+
enum class StrangeEnum(val size: String) {
26+
`60x60`("60x60"),
27+
`70x70`("70x70"),
28+
`80x80`("80x80"),
29+
InvalidFieldName("0x0") // Workaround to pass javac analysis
30+
}
31+
32+
annotation class Anno(val size: StrangeEnum, val name: String, val `A B`: String)
33+
34+
class `!A@`
35+
class `A()B()`
36+
class `A B` {
37+
class C
38+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
2+
public abstract @interface Anno {
3+
4+
public abstract StrangeEnum size();
5+
6+
public abstract java.lang.String name();
7+
}
8+
9+
////////////////////
10+
11+
12+
public enum StrangeEnum {
13+
/*public static final*/ InvalidFieldName /* = new InvalidFieldName(null) */;
14+
@org.jetbrains.annotations.NotNull()
15+
private final java.lang.String size = null;
16+
17+
@org.jetbrains.annotations.NotNull()
18+
public final java.lang.String getSize() {
19+
return null;
20+
}
21+
22+
StrangeEnum(@org.jetbrains.annotations.NotNull()
23+
java.lang.String size) {
24+
}
25+
}
26+
27+
////////////////////
28+
29+
30+
public final class Test {
31+
@org.jetbrains.annotations.NotNull()
32+
public java.lang.String simpleName;
33+
34+
@org.jetbrains.annotations.NotNull()
35+
public final java.lang.String getSimpleName() {
36+
return null;
37+
}
38+
39+
public final void simpleFun() {
40+
}
41+
42+
@Anno(name = "Woofwoof", size = StrangeEnum.InvalidFieldName)
43+
public final void simpleFun2(@org.jetbrains.annotations.NotNull()
44+
java.lang.String a, @org.jetbrains.annotations.NotNull()
45+
java.lang.String b) {
46+
}
47+
48+
public final void strangeFun4(@org.jetbrains.annotations.NotNull()
49+
java.lang.String a, @org.jetbrains.annotations.NotNull()
50+
java.lang.String p1_1899121793) {
51+
}
52+
53+
public Test() {
54+
super();
55+
}
56+
}
Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1 @@
1-
public final class My $ name {
2-
@org.jetbrains.annotations.NotNull()
3-
private final java.lang.String (@\u2022@) = "";
4-
@org.jetbrains.annotations.NotNull()
5-
private final java.lang.String \u041a\u043e\u0442\u043b\u0438\u043d-\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 = "";
61

7-
public final void (^_^)(int )))))) {
8-
}
9-
10-
@org.jetbrains.annotations.NotNull()
11-
public final java.lang.String get(@\u2022@)() {
12-
return null;
13-
}
14-
15-
@org.jetbrains.annotations.NotNull()
16-
public final java.lang.String get\u041a\u043e\u0442\u043b\u0438\u043d-\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440() {
17-
return null;
18-
}
19-
20-
public final void \u3053\u3000\u3068\u3000\u308a\u3000\u3093\uff01() {
21-
}
22-
23-
public My $ name() {
24-
super();
25-
}
26-
}

0 commit comments

Comments
 (0)