Kapt: add JeElementRenderer

This commit is contained in:
Yan Zhulanow
2016-08-02 22:47:00 +03:00
committed by Yan Zhulanow
parent 649b93833c
commit 3eecf78307
5 changed files with 153 additions and 11 deletions

View File

@@ -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

View File

@@ -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 -> "<ERROR>"
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 -> "<ERROR>"
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")
}
}

View File

@@ -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 <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, 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 <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, 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 <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P) = v.visitType(value, p)
}
private abstract class JePrimitiveAnnotationValue : AnnotationValue {
internal abstract class JePrimitiveAnnotationValue : AnnotationValue {
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, 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 <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P) = v.visitArray(value, p)
}
private class JeErrorAnnotationValue(val psi: PsiElement) : AnnotationValue {
internal class JeErrorAnnotationValue(val psi: PsiElement) : AnnotationValue {
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P) = v.visitString(psi.text, p)
override fun getValue() = null
}

View File

@@ -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
}

View File

@@ -55,8 +55,8 @@ class JeTypeElement(override val psi: PsiClass) : JeElement(), TypeElement, JeAn
else -> NestingKind.LOCAL
}
override fun getEnclosedElements(): List<Element> {
val declarations = mutableListOf<Element>()
override fun getEnclosedElements(): List<JeElement> {
val declarations = mutableListOf<JeElement>()
psi.initializers.forEach { declarations += JeClassInitializerExecutableElement(it) }
psi.fields.forEach { declarations += JeVariableElement(it) }
psi.methods.forEach { declarations += JeMethodExecutableElement(it) }