From 0fc92c784b1a59bd51638529cdd587755eef3d1a Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Tue, 2 Aug 2016 22:47:00 +0300 Subject: [PATCH] Kapt: add JeElementRenderer (cherry picked from commit 3eecf78) --- .../processing/impl/KotlinElements.kt | 2 +- .../elements/DefaultJeElementRenderer.kt | 119 ++++++++++++++++++ .../java/model/elements/JeAnnotationValue.kt | 16 +-- .../java/model/elements/JeElementRenderer.kt | 23 ++++ .../java/model/elements/JeTypeElement.kt | 4 +- 5 files changed, 153 insertions(+), 11 deletions(-) create mode 100644 plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/DefaultJeElementRenderer.kt create mode 100644 plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/JeElementRenderer.kt diff --git a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinElements.kt b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinElements.kt index f4f47674af1..9414619e3ed 100644 --- a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinElements.kt +++ b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinElements.kt @@ -71,7 +71,7 @@ class KotlinElements(val javaPsiFacade: JavaPsiFacade, val scope: GlobalSearchSc override fun getBinaryName(type: TypeElement) = JeName((type as JeTypeElement).psi.qualifiedName) //TODO - override fun getDocComment(e: Element?) = "" + override fun getDocComment(e: Element?) = null override fun isDeprecated(e: Element?): Boolean { return (e as? JeAnnotationOwner)?.annotationOwner?.findAnnotation("java.lang.Deprecated") != null diff --git a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/DefaultJeElementRenderer.kt b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/DefaultJeElementRenderer.kt new file mode 100644 index 00000000000..8afe036b7e1 --- /dev/null +++ b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/DefaultJeElementRenderer.kt @@ -0,0 +1,119 @@ +/* + * Copyright 2010-2016 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.java.model.elements + +import org.jetbrains.kotlin.java.model.JeElement +import org.jetbrains.kotlin.java.model.types.* +import javax.lang.model.element.AnnotationMirror +import javax.lang.model.element.AnnotationValue +import javax.lang.model.element.Element +import javax.lang.model.element.ElementKind +import javax.lang.model.type.TypeMirror + +class DefaultJeElementRenderer : JeElementRenderer { + override fun render(element: JeElement): String { + return when (element) { + is JePackageElement -> buildString { + appendln("package ${element.qualifiedName}").appendln() + element.enclosedElements.forEach { appendln(render(it).withMargin()).appendln() } + } + is JeTypeElement -> buildString { + val classType = when (element.kind) { + ElementKind.ANNOTATION_TYPE -> "@interface" + ElementKind.INTERFACE -> "interface" + ElementKind.ENUM -> "enum" + ElementKind.CLASS -> "class" + else -> throw IllegalStateException("Invalid class type: ${element.kind}") + } + appendln(renderModifiers(element) + classType + ' ' + element.simpleName + " {") + appendln(element.enclosedElements.joinToString(LINE_SEPARATOR.repeat(2)) { render(it).withMargin() }) + append("}") + } + is JeVariableElement -> renderModifiers(element) + renderType(element.asType()) + " " + element.simpleName + is JeMethodExecutableElement -> buildString { + append(renderModifiers(element) + renderType(element.returnType, noneAsVoid = true) + " " + element.simpleName) + append(element.parameters.joinToString(prefix = "(", postfix = ")") { renderType(it.asType()) + " " + it.simpleName }) + } + is JeClassInitializerExecutableElement -> renderModifiers(element) + "{}" + else -> throw IllegalArgumentException("Unsupported element: $element") + } + } + + private fun renderType(type: TypeMirror, noneAsVoid: Boolean = false): String { + return when (type) { + is JeNullType -> "null" + is JeVoidType -> "void" + is JeErrorType -> "" + is JeNoneType -> if (noneAsVoid) "void" else throw IllegalArgumentException("Unexpected 'none' type") + is JePsiType -> type.psiType.getCanonicalText(false) + else -> throw IllegalArgumentException("Unsupported type: $type") + } + } + + private fun renderModifiers(element: Element): String { + val renderedAnnotations = renderAnnotations(element) + val modifiers = element.modifiers + + return if (modifiers.isEmpty()) + renderedAnnotations + else + renderedAnnotations + modifiers.map { it.name.toLowerCase() }.joinToString(" ", postfix = " ") + } + + private fun renderAnnotations(element: Element): String { + val annotations = element.annotationMirrors + if (annotations.isEmpty()) return "" + return annotations.joinToString(LINE_SEPARATOR, postfix = LINE_SEPARATOR) { renderAnnotation(it) } + } + + private fun renderAnnotation(anno: AnnotationMirror): String { + val name = "@" + renderType(anno.annotationType) + val args = anno.elementValues + if (args.isEmpty()) return name + + return name + args + .map { it.key.simpleName.toString() + " = " + renderAnnotationValue(it.value) } + .joinToString(prefix = "(", postfix = ")") + } + + private fun renderAnnotationValue(value: AnnotationValue): String { + return when (value) { + is JeAnnotationAnnotationValue -> renderAnnotation(value.value) + is JeArrayAnnotationValue -> value.value.joinToString(prefix = "{ ", postfix = " }") { renderAnnotationValue(it) } + is JeEnumValueAnnotationValue -> value.value.simpleName.toString() + is JeErrorAnnotationValue -> "" + is JeExpressionAnnotationValue, is JeLiteralAnnotationValue -> value.value?.let { renderConstantValue(it) } ?: "null" + is JeTypeAnnotationValue -> renderType(value.value) + ".class" + else -> throw IllegalArgumentException("Unsupported annotation value: $value") + } + } + + private fun renderConstantValue(value: Any?): String { + return when (value) { + null -> "null" + is String -> "\"" + value.replace("\"", "\\\"") + "\"" + else -> value.toString() + } + } + + private fun String.withMargin() = lines().map { MARGIN + it }.joinToString(LINE_SEPARATOR) + + private companion object { + val MARGIN = " " + val LINE_SEPARATOR: String = System.getProperty("line.separator") + } +} \ No newline at end of file diff --git a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/JeAnnotationValue.kt b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/JeAnnotationValue.kt index 5a620f98b22..9319abe0f3a 100644 --- a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/JeAnnotationValue.kt +++ b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/JeAnnotationValue.kt @@ -40,22 +40,22 @@ fun JeAnnotationValue(psi: PsiAnnotationMemberValue): AnnotationValue = when (ps else -> throw AssertionError("Unsupported annotation element value: $psi") } -private class JeAnnotationAnnotationValue(val psi: PsiAnnotation) : AnnotationValue { +internal class JeAnnotationAnnotationValue(val psi: PsiAnnotation) : AnnotationValue { override fun getValue() = JeAnnotationMirror(psi) override fun accept(v: AnnotationValueVisitor, p: P) = v.visitAnnotation(value, p) } -private class JeEnumValueAnnotationValue(val psi: PsiEnumConstant) : AnnotationValue { +internal class JeEnumValueAnnotationValue(val psi: PsiEnumConstant) : AnnotationValue { override fun getValue() = JeVariableElement(psi) override fun accept(v: AnnotationValueVisitor, p: P) = v.visitEnumConstant(value, p) } -private class JeTypeAnnotationValue(val psi: PsiClassObjectAccessExpression) : AnnotationValue { +internal class JeTypeAnnotationValue(val psi: PsiClassObjectAccessExpression) : AnnotationValue { override fun getValue() = psi.operand.type.toJeType(psi.manager) override fun accept(v: AnnotationValueVisitor, p: P) = v.visitType(value, p) } -private abstract class JePrimitiveAnnotationValue : AnnotationValue { +internal abstract class JePrimitiveAnnotationValue : AnnotationValue { override fun accept(v: AnnotationValueVisitor, p: P): R { val value = this.value return when (value) { @@ -73,20 +73,20 @@ private abstract class JePrimitiveAnnotationValue : AnnotationValue { } } -private class JeLiteralAnnotationValue(val psi: PsiLiteral) : JePrimitiveAnnotationValue() { +internal class JeLiteralAnnotationValue(val psi: PsiLiteral) : JePrimitiveAnnotationValue() { override fun getValue() = psi.value } -private class JeExpressionAnnotationValue(val psi: PsiExpression) : JePrimitiveAnnotationValue() { +internal class JeExpressionAnnotationValue(val psi: PsiExpression) : JePrimitiveAnnotationValue() { override fun getValue() = JavaPsiFacade.getInstance(psi.project).constantEvaluationHelper.computeConstantExpression(psi) } -private class JeArrayAnnotationValue(val psi: PsiArrayInitializerMemberValue) : AnnotationValue { +internal class JeArrayAnnotationValue(val psi: PsiArrayInitializerMemberValue) : AnnotationValue { override fun getValue() = psi.initializers.map { JeAnnotationValue(it) } override fun accept(v: AnnotationValueVisitor, p: P) = v.visitArray(value, p) } -private class JeErrorAnnotationValue(val psi: PsiElement) : AnnotationValue { +internal class JeErrorAnnotationValue(val psi: PsiElement) : AnnotationValue { override fun accept(v: AnnotationValueVisitor, p: P) = v.visitString(psi.text, p) override fun getValue() = null } \ No newline at end of file diff --git a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/JeElementRenderer.kt b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/JeElementRenderer.kt new file mode 100644 index 00000000000..4820297f6ac --- /dev/null +++ b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/JeElementRenderer.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2010-2016 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.java.model.elements + +import org.jetbrains.kotlin.java.model.JeElement + +interface JeElementRenderer { + fun render(element: JeElement): String +} \ No newline at end of file diff --git a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/JeTypeElement.kt b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/JeTypeElement.kt index 0462602a1c6..7888ad2b782 100644 --- a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/JeTypeElement.kt +++ b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/elements/JeTypeElement.kt @@ -55,8 +55,8 @@ class JeTypeElement(override val psi: PsiClass) : JeElement(), TypeElement, JeAn else -> NestingKind.LOCAL } - override fun getEnclosedElements(): List { - val declarations = mutableListOf() + override fun getEnclosedElements(): List { + val declarations = mutableListOf() psi.initializers.forEach { declarations += JeClassInitializerExecutableElement(it) } psi.fields.forEach { declarations += JeVariableElement(it) } psi.methods.forEach { declarations += JeMethodExecutableElement(it) }