Kapt: Forbid illegal Java identifiers in Enum value literals
This commit is contained in:
@@ -17,12 +17,11 @@
|
|||||||
package org.jetbrains.kotlin.kapt3.javac
|
package org.jetbrains.kotlin.kapt3.javac
|
||||||
|
|
||||||
import com.sun.tools.javac.tree.JCTree
|
import com.sun.tools.javac.tree.JCTree
|
||||||
import com.sun.tools.javac.util.Context
|
import com.sun.tools.javac.util.*
|
||||||
import com.sun.tools.javac.util.JCDiagnostic
|
|
||||||
import com.sun.tools.javac.util.Log
|
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
|
||||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
|
import org.jetbrains.kotlin.kapt3.KaptContext
|
||||||
import org.jetbrains.kotlin.kapt3.util.MessageCollectorBackedWriter
|
import org.jetbrains.kotlin.kapt3.util.MessageCollectorBackedWriter
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import javax.tools.JavaFileObject
|
import javax.tools.JavaFileObject
|
||||||
@@ -38,6 +37,29 @@ class KaptJavaLog(
|
|||||||
context.put(Log.outKey, noticeWriter)
|
context.put(Log.outKey, noticeWriter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val reportedDiagnostics: List<JCDiagnostic>
|
||||||
|
get() = _reportedDiagnostics
|
||||||
|
|
||||||
|
private val _reportedDiagnostics = mutableListOf<JCDiagnostic>()
|
||||||
|
|
||||||
|
override fun flush(kind: WriterKind?) {
|
||||||
|
super.flush(kind)
|
||||||
|
|
||||||
|
val diagnosticKind = when (kind) {
|
||||||
|
WriterKind.ERROR -> JCDiagnostic.DiagnosticType.ERROR
|
||||||
|
WriterKind.WARNING -> JCDiagnostic.DiagnosticType.WARNING
|
||||||
|
WriterKind.NOTICE -> JCDiagnostic.DiagnosticType.NOTE
|
||||||
|
else -> return
|
||||||
|
}
|
||||||
|
|
||||||
|
_reportedDiagnostics.removeAll { it.type == diagnosticKind }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun flush() {
|
||||||
|
super.flush()
|
||||||
|
_reportedDiagnostics.clear()
|
||||||
|
}
|
||||||
|
|
||||||
override fun report(diagnostic: JCDiagnostic) {
|
override fun report(diagnostic: JCDiagnostic) {
|
||||||
if (diagnostic.type == JCDiagnostic.DiagnosticType.ERROR && diagnostic.code in IGNORED_DIAGNOSTICS) {
|
if (diagnostic.type == JCDiagnostic.DiagnosticType.ERROR && diagnostic.code in IGNORED_DIAGNOSTICS) {
|
||||||
return
|
return
|
||||||
@@ -61,6 +83,7 @@ class KaptJavaLog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_reportedDiagnostics += diagnostic
|
||||||
super.report(diagnostic)
|
super.report(diagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,4 +137,8 @@ class KaptJavaLog(
|
|||||||
class DiagnosticInterceptorData {
|
class DiagnosticInterceptorData {
|
||||||
var files: Map<JavaFileObject, JCTree.JCCompilationUnit> = emptyMap()
|
var files: Map<JavaFileObject, JCTree.JCCompilationUnit> = emptyMap()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KaptContext<*>.kaptError(text: String): JCDiagnostic {
|
||||||
|
return JCDiagnostic.Factory.instance(context).error(null, null, "proc.messager", text)
|
||||||
}
|
}
|
||||||
+6
-1
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
|||||||
import org.jetbrains.kotlin.kapt3.*
|
import org.jetbrains.kotlin.kapt3.*
|
||||||
import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
|
import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
|
||||||
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
|
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
|
||||||
|
import org.jetbrains.kotlin.kapt3.javac.kaptError
|
||||||
import org.jetbrains.kotlin.kapt3.util.*
|
import org.jetbrains.kotlin.kapt3.util.*
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -787,7 +788,11 @@ 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).takeIf { isValidIdentifier(it) } ?: "InvalidFieldName"
|
val valueName = (value[1] as String).takeIf { isValidIdentifier(it) } ?: run {
|
||||||
|
kaptContext.compiler.log.report(kaptContext.kaptError("'${value[1]}' is an invalid Java enum value name"))
|
||||||
|
"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) })
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.kapt3.test
|
|||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import com.sun.tools.javac.comp.CompileStates
|
import com.sun.tools.javac.comp.CompileStates
|
||||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit
|
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit
|
||||||
|
import com.sun.tools.javac.util.JCDiagnostic
|
||||||
import com.sun.tools.javac.util.Log
|
import com.sun.tools.javac.util.Log
|
||||||
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
|
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
|
||||||
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
|
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
|
||||||
@@ -28,6 +29,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
|
|||||||
import org.jetbrains.kotlin.kapt3.Kapt3BuilderFactory
|
import org.jetbrains.kotlin.kapt3.Kapt3BuilderFactory
|
||||||
import org.jetbrains.kotlin.kapt3.KaptContext
|
import org.jetbrains.kotlin.kapt3.KaptContext
|
||||||
import org.jetbrains.kotlin.kapt3.doAnnotationProcessing
|
import org.jetbrains.kotlin.kapt3.doAnnotationProcessing
|
||||||
|
import org.jetbrains.kotlin.kapt3.javac.KaptJavaLog
|
||||||
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter
|
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter
|
||||||
import org.jetbrains.kotlin.kapt3.util.KaptLogger
|
import org.jetbrains.kotlin.kapt3.util.KaptLogger
|
||||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
|
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
|
||||||
@@ -38,6 +40,7 @@ import org.jetbrains.kotlin.test.util.trimTrailingWhitespacesAndAddNewlineAtEOF
|
|||||||
import org.jetbrains.kotlin.utils.PathUtil
|
import org.jetbrains.kotlin.utils.PathUtil
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
|
import java.util.*
|
||||||
import com.sun.tools.javac.util.List as JavacList
|
import com.sun.tools.javac.util.List as JavacList
|
||||||
|
|
||||||
abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
||||||
@@ -96,9 +99,17 @@ abstract class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3T
|
|||||||
override fun check(kaptContext: KaptContext<GenerationState>, txtFile: File, wholeFile: File) {
|
override fun check(kaptContext: KaptContext<GenerationState>, txtFile: File, wholeFile: File) {
|
||||||
fun isOptionSet(name: String) = wholeFile.useLines { lines -> lines.any { it.trim() == "// $name" } }
|
fun isOptionSet(name: String) = wholeFile.useLines { lines -> lines.any { it.trim() == "// $name" } }
|
||||||
|
|
||||||
|
fun getOptionValues(name: String) = wholeFile.useLines { lines ->
|
||||||
|
lines.filter { it.startsWith("// $name") }
|
||||||
|
.map { it.drop(name.length + 3).trim() }
|
||||||
|
.filter { it.isNotEmpty() }
|
||||||
|
.toList()
|
||||||
|
}
|
||||||
|
|
||||||
val generateNonExistentClass = isOptionSet("NON_EXISTENT_CLASS")
|
val generateNonExistentClass = isOptionSet("NON_EXISTENT_CLASS")
|
||||||
val correctErrorTypes = isOptionSet("CORRECT_ERROR_TYPES")
|
val correctErrorTypes = isOptionSet("CORRECT_ERROR_TYPES")
|
||||||
val validate = !isOptionSet("NO_VALIDATION")
|
val validate = !isOptionSet("NO_VALIDATION")
|
||||||
|
val expectedErrors = getOptionValues("EXPECTED_ERROR").sorted()
|
||||||
|
|
||||||
val javaFiles = convert(kaptContext, generateNonExistentClass, correctErrorTypes)
|
val javaFiles = convert(kaptContext, generateNonExistentClass, correctErrorTypes)
|
||||||
|
|
||||||
@@ -111,8 +122,23 @@ abstract class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3T
|
|||||||
.let { removeMetadataAnnotationContents(it) }
|
.let { removeMetadataAnnotationContents(it) }
|
||||||
|
|
||||||
if (kaptContext.compiler.shouldStop(CompileStates.CompileState.ENTER)) {
|
if (kaptContext.compiler.shouldStop(CompileStates.CompileState.ENTER)) {
|
||||||
Log.instance(kaptContext.context).flush()
|
val log = Log.instance(kaptContext.context) as KaptJavaLog
|
||||||
error("There were errors during analysis. See errors above. Stubs:\n\n$actual")
|
|
||||||
|
val actualErrors = log.reportedDiagnostics
|
||||||
|
.filter { it.type == JCDiagnostic.DiagnosticType.ERROR }
|
||||||
|
.map { it.getMessage(Locale.US).lines().first() }
|
||||||
|
.sorted()
|
||||||
|
|
||||||
|
log.flush()
|
||||||
|
|
||||||
|
if (expectedErrors.isEmpty()) {
|
||||||
|
error("There were errors during analysis. See errors above. Stubs:\n\n$actual")
|
||||||
|
} else if (actualErrors != expectedErrors) {
|
||||||
|
error("Expected error matching assertion. Expected: \n"
|
||||||
|
+ expectedErrors.joinToString("\n") { "'$it'" }
|
||||||
|
+ "\n, found: \n"
|
||||||
|
+ actualErrors.joinToString("\n") { "'$it'" })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
KotlinTestUtils.assertEqualsToFile(txtFile, actual)
|
KotlinTestUtils.assertEqualsToFile(txtFile, actual)
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -120,6 +120,12 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("invalidFieldName.kt")
|
||||||
|
public void testInvalidFieldName() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/invalidFieldName.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("javaKeywords.kt")
|
@TestMetadata("javaKeywords.kt")
|
||||||
public void testJavaKeywords() throws Exception {
|
public void testJavaKeywords() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/javaKeywords.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/javaKeywords.kt");
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// EXPECTED_ERROR 'WHI-TE' is an invalid Java enum value name
|
||||||
|
// EXPECTED_ERROR an enum annotation value must be an enum constant
|
||||||
|
// EXPECTED_ERROR cannot find symbol
|
||||||
|
|
||||||
|
enum class Color {
|
||||||
|
BLACK, `WHI-TE`
|
||||||
|
}
|
||||||
|
|
||||||
|
@Anno(Color.`WHI-TE`)
|
||||||
|
annotation class Anno(val color: Color)
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
@kotlin.Metadata()
|
||||||
|
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||||
|
@Anno(color = Color.InvalidFieldName)
|
||||||
|
public abstract @interface Anno {
|
||||||
|
|
||||||
|
public abstract Color color();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
@kotlin.Metadata()
|
||||||
|
public enum Color {
|
||||||
|
/*public static final*/ BLACK /* = new BLACK() */;
|
||||||
|
|
||||||
|
Color() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// EXPECTED_ERROR '60x60' is an invalid Java enum value name
|
||||||
|
|
||||||
class `:)` {
|
class `:)` {
|
||||||
lateinit val f: String
|
lateinit val f: String
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user