diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt index 42823f59e2b..aa3f839c4ea 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.kapt3.stubs import com.sun.tools.javac.code.Flags import com.sun.tools.javac.code.TypeTag import com.sun.tools.javac.file.JavacFileManager +import com.sun.tools.javac.parser.Tokens import com.sun.tools.javac.tree.JCTree import com.sun.tools.javac.tree.JCTree.* import com.sun.tools.javac.tree.TreeMaker @@ -27,6 +28,7 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.kapt3.* import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject +import org.jetbrains.kotlin.kapt3.stubs.Kapt3StubUtils.* import org.jetbrains.kotlin.kapt3.util.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.DescriptorUtils @@ -69,6 +71,12 @@ class ClassFileToSourceStubConverter( "org.jetbrains.annotations.", // Nullable/NotNull, ReadOnly, Mutable "kotlin.jvm.", "kotlin.Metadata" // Kotlin annotations from runtime ) + + private val JAVA_KEYWORD_FILTER_REGEX = "[a-z]+".toRegex() + + private val JAVA_KEYWORDS = Tokens.TokenKind.values() + .filter { JAVA_KEYWORD_FILTER_REGEX.matches(getTokenName(it)) } + .mapTo(hashSetOf(), ::getTokenName) } private val _bindings = mutableMapOf() @@ -210,7 +218,7 @@ class ClassFileToSourceStubConverter( return treeMaker.ClassDef( modifiers, - treeMaker.name(simpleName), + treeMaker.name(getNonKeywordName(simpleName)), genericType.typeParameters, if (hasSuperClass) genericType.superClass else null, genericType.interfaces, @@ -222,7 +230,7 @@ class ClassFileToSourceStubConverter( val descriptor = kaptContext.origins[field]?.descriptor val modifiers = convertModifiers(field.access, ElementKind.FIELD, packageFqName, field.visibleAnnotations, field.invisibleAnnotations) - val name = treeMaker.name(field.name) + val name = treeMaker.name(getNonKeywordName(field.name)) val type = Type.getType(field.desc) // Enum type must be an identifier (Javac requirement) @@ -260,7 +268,7 @@ class ClassFileToSourceStubConverter( } val isConstructor = method.name == "" - val name = treeMaker.name(method.name) + val name = treeMaker.name(getNonKeywordName(method.name)) val modifiers = convertModifiers( if (containingClass.isEnum() && isConstructor) @@ -286,7 +294,7 @@ class ClassFileToSourceStubConverter( info.visibleAnnotations, info.invisibleAnnotations) - val name = treeMaker.name(info.name) + val name = treeMaker.name(getNonKeywordName(info.name)) val type = treeMaker.Type(info.type) treeMaker.VarDef(modifiers, name, type, null) } @@ -394,6 +402,12 @@ class ClassFileToSourceStubConverter( return ifNonError() } + private fun getNonKeywordName(name: String): String { + // 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 + '_' + return name + } + private inline fun getNotAnonymousType(descriptor: DeclarationDescriptor?, f: () -> T): T { if (descriptor is CallableDescriptor) { val returnTypeDescriptor = descriptor.returnType?.constructor?.declarationDescriptor diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/Kapt3StubUtils.java b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/Kapt3StubUtils.java new file mode 100644 index 00000000000..52fc163e8dc --- /dev/null +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/Kapt3StubUtils.java @@ -0,0 +1,29 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.kapt3.stubs; + +import com.sun.tools.javac.parser.Tokens; +import org.jetbrains.annotations.NotNull; + +public class Kapt3StubUtils { + @NotNull + public static String getTokenName(@NotNull Tokens.TokenKind kind) { + // This is a work-around. `name` can't be called from Kotlin, as it clashes with the `name` enum property. + String name = kind.name; + return (name == null) ? "" : name; + } +} diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java index fee967332dc..5093ec4d662 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java @@ -108,6 +108,12 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi doTest(fileName); } + @TestMetadata("javaKeywords.kt") + public void testJavaKeywords() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/javaKeywords.kt"); + doTest(fileName); + } + @TestMetadata("jvmOverloads.kt") public void testJvmOverloads() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/jvmOverloads.kt"); diff --git a/plugins/kapt3/testData/converter/javaKeywords.kt b/plugins/kapt3/testData/converter/javaKeywords.kt new file mode 100644 index 00000000000..d380d3ded25 --- /dev/null +++ b/plugins/kapt3/testData/converter/javaKeywords.kt @@ -0,0 +1,4 @@ +class default { + lateinit val extends: String + fun implements(instanceof: Int) {} +} \ No newline at end of file diff --git a/plugins/kapt3/testData/converter/javaKeywords.txt b/plugins/kapt3/testData/converter/javaKeywords.txt new file mode 100644 index 00000000000..c5755b6b92d --- /dev/null +++ b/plugins/kapt3/testData/converter/javaKeywords.txt @@ -0,0 +1,14 @@ +public final class _default_ { + public java.lang.String _extends_; + + public final java.lang.String getExtends() { + return null; + } + + public final void _implements_(int _instanceof_) { + } + + public _default_() { + super(); + } +} diff --git a/plugins/kapt3/testData/converter/kt14998.txt b/plugins/kapt3/testData/converter/kt14998.txt index e2767d2a172..1692663ba7c 100644 --- a/plugins/kapt3/testData/converter/kt14998.txt +++ b/plugins/kapt3/testData/converter/kt14998.txt @@ -3,7 +3,7 @@ public final class Outer { public final void nonAbstract(java.lang.String s, int i) { } - public abstract void abstract(java.lang.String p0, int p1); + public abstract void _abstract_(java.lang.String p0, int p1); public Outer() { super();