Corrections on code review

This commit is contained in:
Valentin Kipyatkov
2015-03-04 17:41:44 +03:00
parent ac6a56761e
commit 4a29e968d0
3 changed files with 76 additions and 48 deletions
@@ -33,10 +33,10 @@ class AnnotationConverter(private val converter: Converter) {
private fun convertAnnotationsOnly(owner: PsiModifierListOwner): Annotations { private fun convertAnnotationsOnly(owner: PsiModifierListOwner): Annotations {
val modifierList = owner.getModifierList() val modifierList = owner.getModifierList()
val annotations = modifierList?.getAnnotations()?.filter { it.getQualifiedName() !in annotationsToRemove }.orEmpty() val annotations = modifierList?.getAnnotations()?.filter { it.getQualifiedName() !in annotationsToRemove }
val newLines = run { var convertedAnnotations: List<Annotation> = if (annotations != null && annotations.isNotEmpty()) {
if (!modifierList!!.isInSingleLine()) { val newLines = if (!modifierList!!.isInSingleLine()) {
true true
} }
else { else {
@@ -47,30 +47,31 @@ class AnnotationConverter(private val converter: Converter) {
} }
if (child is PsiWhiteSpace) !child!!.isInSingleLine() else false if (child is PsiWhiteSpace) !child!!.isInSingleLine() else false
} }
annotations.map { convertAnnotation(it, owner is PsiLocalVariable, newLines) }.filterNotNull() //TODO: brackets are also needed for local classes
}
else {
listOf()
} }
var list = annotations.map { convertAnnotation(it, owner is PsiLocalVariable, newLines) }.filterNotNull() //TODO: brackets are also needed for local classes
if (owner is PsiDocCommentOwner) { if (owner is PsiDocCommentOwner) {
val deprecatedAnnotation = convertDeprecatedJavadocTag(owner) val deprecatedAnnotation = convertDeprecatedJavadocTag(owner)
if (deprecatedAnnotation != null) { if (deprecatedAnnotation != null) {
list += deprecatedAnnotation convertedAnnotations += deprecatedAnnotation
} }
} }
return if (list.isEmpty()) Annotations.Empty else Annotations(list).assignNoPrototype() return Annotations(convertedAnnotations).assignNoPrototype()
} }
private fun convertDeprecatedJavadocTag(element: PsiDocCommentOwner): Annotation? { private fun convertDeprecatedJavadocTag(element: PsiDocCommentOwner): Annotation? {
val deprecatedTag = element.getDocComment()?.findTagByName("deprecated") val deprecatedTag = element.getDocComment()?.findTagByName("deprecated") ?: return null
if (deprecatedTag != null) { val deferredExpression = converter.deferredElement<Expression> {
val deferredExpression = converter.deferredElement<Expression> { LiteralExpression("\"" + StringUtil.escapeStringCharacters(deprecatedTag.content()) + "\"").assignNoPrototype()
LiteralExpression("\"${StringUtil.escapeStringCharacters(deprecatedTag.content())}\"").assignNoPrototype()
}
return Annotation(Identifier("deprecated").assignPrototype(deprecatedTag.getNameElement()),
listOf(null to deferredExpression), false, true)
.assignPrototype(deprecatedTag)
} }
return null return Annotation(Identifier("deprecated").assignPrototype(deprecatedTag.getNameElement()),
listOf(null to deferredExpression), false, true)
.assignPrototype(deprecatedTag)
} }
private fun convertModifiersToAnnotations(owner: PsiModifierListOwner): Annotations { private fun convertModifiersToAnnotations(owner: PsiModifierListOwner): Annotations {
@@ -61,7 +61,8 @@ class CodeBuilder(private val topElement: PsiElement?) {
private fun appendCommentOrWhiteSpace(element: PsiElement) { private fun appendCommentOrWhiteSpace(element: PsiElement) {
if (element is PsiDocComment) { if (element is PsiDocComment) {
append(DocCommentConverter.convertDocComment(element), false) append(DocCommentConverter.convertDocComment(element), false)
} else { }
else {
append(element.getText()!!, element.isEndOfLineComment()) append(element.getText()!!, element.isEndOfLineComment())
} }
} }
@@ -31,45 +31,49 @@ import java.util.Stack
object DocCommentConverter { object DocCommentConverter {
fun convertDocComment(docComment: PsiDocComment): String { fun convertDocComment(docComment: PsiDocComment): String {
val htmlTextBuilder = StringBuilder() val html = StringBuilder {
htmlTextBuilder.appendJavadocElements(docComment.getDescriptionElements()) appendJavadocElements(docComment.getDescriptionElements())
docComment.getTags().filter { it.getName() != "deprecated" }.forEach {
if (it.getName() == "see") { for (tag in docComment.getTags()) {
htmlTextBuilder.append("@see ${convertJavadocLink(it.content())}\n") when (tag.getName()) {
} else { "deprecated" -> continue
htmlTextBuilder.appendJavadocElements(it.getChildren()).append("\n") "see" -> append("@see ${convertJavadocLink(tag.content())}\n")
else -> appendJavadocElements(tag.getChildren()).append("\n")
}
} }
} }.toString()
val html = htmlTextBuilder.toString()
if (html.trim().isEmpty() && docComment.findTagByName("deprecated") != null) { if (html.trim().isEmpty() && docComment.findTagByName("deprecated") != null) {
// @deprecated was the only content of the doc comment; we can drop the comment // @deprecated was the only content of the doc comment; we can drop the comment
return "" return ""
} }
val htmlFile = PsiFileFactory.getInstance(docComment.getProject()).createFileFromText( val htmlFile = PsiFileFactory.getInstance(docComment.getProject()).createFileFromText(
"javadoc.html", HtmlFileType.INSTANCE, html) "javadoc.html", HtmlFileType.INSTANCE, html)
val htmlToMarkdownConverter = HtmlToMarkdownConverter() val htmlToMarkdownConverter = HtmlToMarkdownConverter()
htmlFile.accept(htmlToMarkdownConverter) htmlFile.accept(htmlToMarkdownConverter)
return htmlToMarkdownConverter.markdownBuilder.toString() return htmlToMarkdownConverter.result
} }
fun StringBuilder.appendJavadocElements(elements: Array<PsiElement>): StringBuilder { private fun StringBuilder.appendJavadocElements(elements: Array<PsiElement>): StringBuilder {
elements.forEach { elements.forEach {
if (it is PsiInlineDocTag) { if (it is PsiInlineDocTag) {
append(convertInlineDocTag(it)) append(convertInlineDocTag(it))
} else { }
else {
append(it.getText()) append(it.getText())
} }
} }
return this return this
} }
fun convertInlineDocTag(tag: PsiInlineDocTag) = when(tag.getName()) { private fun convertInlineDocTag(tag: PsiInlineDocTag) = when(tag.getName()) {
"code", "literal" -> { "code", "literal" -> {
val text = StringBuilder() val text = tag.getDataElements().map { it.getText() }.join()
tag.getDataElements().forEach { text.append(it.getText()) } val escaped = StringUtil.escapeXml(text.trimLeading())
val escaped = StringUtil.escapeXml(text.toString().trimLeading())
if (tag.getName() == "code") "<code>$escaped</code>" else escaped if (tag.getName() == "code") "<code>$escaped</code>" else escaped
} }
"link", "linkplain" -> { "link", "linkplain" -> {
val valueElement = tag.linkElement() val valueElement = tag.linkElement()
val labelText = tag.getDataElements().firstOrNull { it is PsiDocToken }?.getText() ?: "" val labelText = tag.getDataElements().firstOrNull { it is PsiDocToken }?.getText() ?: ""
@@ -77,25 +81,30 @@ object DocCommentConverter {
val linkText = if (labelText.isEmpty()) kdocLink else StringUtil.escapeXml(labelText) val linkText = if (labelText.isEmpty()) kdocLink else StringUtil.escapeXml(labelText)
"<a docref=\"$kdocLink\">$linkText</a>" "<a docref=\"$kdocLink\">$linkText</a>"
} }
else -> tag.getText() else -> tag.getText()
} }
fun convertJavadocLink(link: String?): String = private fun convertJavadocLink(link: String?): String =
if (link != null) link.substringBefore('(').replace('#', '.') else "" if (link != null) link.substringBefore('(').replace('#', '.') else ""
private fun PsiDocTag.linkElement(): PsiElement? = private fun PsiDocTag.linkElement(): PsiElement? =
getValueElement() ?: getDataElements().firstOrNull { it !is PsiWhiteSpace } getValueElement() ?: getDataElements().firstOrNull { it !is PsiWhiteSpace }
class HtmlToMarkdownConverter() : XmlRecursiveElementVisitor() { private class HtmlToMarkdownConverter() : XmlRecursiveElementVisitor() {
enum class ListType { Ordered; Unordered } private enum class ListType { Ordered; Unordered }
val markdownBuilder = StringBuilder("/**") val result: String
var afterLineBreak: Boolean = false get() = markdownBuilder.toString()
var whitespaceIsPartOfText: Boolean = true
var currentListType = ListType.Unordered private val markdownBuilder = StringBuilder("/**")
private var afterLineBreak = false
private var whitespaceIsPartOfText = true
private var currentListType = ListType.Unordered
override fun visitWhiteSpace(space: PsiWhiteSpace) { override fun visitWhiteSpace(space: PsiWhiteSpace) {
super.visitWhiteSpace(space) super.visitWhiteSpace(space)
if (whitespaceIsPartOfText) { if (whitespaceIsPartOfText) {
appendPendingText() appendPendingText()
markdownBuilder.append(space.getText()) markdownBuilder.append(space.getText())
@@ -107,6 +116,7 @@ object DocCommentConverter {
override fun visitElement(element: PsiElement) { override fun visitElement(element: PsiElement) {
super.visitElement(element) super.visitElement(element)
val tokenType = element.getNode().getElementType() val tokenType = element.getNode().getElementType()
if (tokenType == XmlTokenType.XML_DATA_CHARACTERS || tokenType == XmlTokenType.XML_CHAR_ENTITY_REF) { if (tokenType == XmlTokenType.XML_DATA_CHARACTERS || tokenType == XmlTokenType.XML_CHAR_ENTITY_REF) {
appendPendingText() appendPendingText()
@@ -121,13 +131,15 @@ object DocCommentConverter {
appendPendingText() appendPendingText()
val (openingMarkdown, closingMarkdown) = getMarkdownForTag(tag, atLineStart) val (openingMarkdown, closingMarkdown) = getMarkdownForTag(tag, atLineStart)
markdownBuilder.append(openingMarkdown) markdownBuilder.append(openingMarkdown)
super.visitXmlTag(tag) super.visitXmlTag(tag)
markdownBuilder.append(closingMarkdown) markdownBuilder.append(closingMarkdown)
currentListType = oldListType currentListType = oldListType
} }
} }
override fun visitXmlText(text: XmlText?) { override fun visitXmlText(text: XmlText) {
withWhitespaceAsPartOfText(true) { withWhitespaceAsPartOfText(true) {
super.visitXmlText(text) super.visitXmlText(text)
} }
@@ -138,27 +150,40 @@ object DocCommentConverter {
whitespaceIsPartOfText = newValue whitespaceIsPartOfText = newValue
try { try {
block() block()
} finally { }
finally {
whitespaceIsPartOfText = oldValue whitespaceIsPartOfText = oldValue
} }
} }
private fun getMarkdownForTag(tag: XmlTag, atLineStart: Boolean): Pair<String, String> = when(tag.getName()) { private fun getMarkdownForTag(tag: XmlTag, atLineStart: Boolean): Pair<String, String> = when(tag.getName()) {
"b", "strong" -> "**" to "**" "b", "strong" -> "**" to "**"
"p" -> if (atLineStart) "\n * " to "" else "\n *\n *" to "" "p" -> if (atLineStart) "\n * " to "" else "\n *\n *" to ""
"i", "em" -> "*" to "*" "i", "em" -> "*" to "*"
"s", "del" -> "~~" to "~~" "s", "del" -> "~~" to "~~"
"code" -> "`" to "`" "code" -> "`" to "`"
"a" -> if (tag.getAttributeValue("docref") != null) {
val docRef = tag.getAttributeValue("docref") "a" -> {
val innerText = tag.getValue().getText() if (tag.getAttributeValue("docref") != null) {
if (docRef == innerText) "[" to "]" else "[" to "][$docRef]" val docRef = tag.getAttributeValue("docref")
} else { val innerText = tag.getValue().getText()
"[" to "](${tag.getAttributeValue("href")})" if (docRef == innerText) "[" to "]" else "[" to "][$docRef]"
}
else {
"[" to "](${tag.getAttributeValue("href")})"
}
} }
"ul" -> { currentListType = ListType.Unordered; "" to "" } "ul" -> { currentListType = ListType.Unordered; "" to "" }
"ol" -> { currentListType = ListType.Ordered; "" to "" } "ol" -> { currentListType = ListType.Ordered; "" to "" }
"li" -> if (currentListType == ListType.Unordered) " * " to "" else " 1. " to "" "li" -> if (currentListType == ListType.Unordered) " * " to "" else " 1. " to ""
else -> "" to "" else -> "" to ""
} }
@@ -169,8 +194,9 @@ object DocCommentConverter {
} }
} }
override fun visitXmlFile(file: XmlFile?) { override fun visitXmlFile(file: XmlFile) {
super.visitXmlFile(file) super.visitXmlFile(file)
markdownBuilder.append(" */") markdownBuilder.append(" */")
} }
} }