ConvertToConcatenatedStringIntention - minor code improvements + fixed bug

This commit is contained in:
Valentin Kipyatkov
2015-04-14 22:04:40 +03:00
parent b980d98af6
commit 0334ad1152
5 changed files with 34 additions and 27 deletions
@@ -339,8 +339,6 @@ convert.to.for.each.function.call.intention=Replace with a forEach function call
convert.to.for.each.function.call.intention.family=Replace with a forEach Function Call convert.to.for.each.function.call.intention.family=Replace with a forEach Function Call
convert.to.string.template=Convert concatenation to template convert.to.string.template=Convert concatenation to template
convert.to.string.template.family=Convert Concatenation to Template convert.to.string.template.family=Convert Concatenation to Template
convert.to.concatenated.string.intention=Convert template to concatenated string
convert.to.concatenated.string.intention.family=Convert Template to Concatenated String
property.is.implemented.too.many=Has implementations property.is.implemented.too.many=Has implementations
property.is.overridden.too.many=Is overridden in subclasses property.is.overridden.too.many=Is overridden in subclasses
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContextUtils import org.jetbrains.kotlin.resolve.BindingContextUtils
public class ConvertToConcatenatedStringIntention : JetSelfTargetingOffsetIndependentIntention<JetStringTemplateExpression>("convert.to.concatenated.string.intention", javaClass()) { public class ConvertToConcatenatedStringIntention : JetSelfTargetingOffsetIndependentIntention<JetStringTemplateExpression>(javaClass(), "Convert template to concatenated string") {
override fun isApplicableTo(element: JetStringTemplateExpression): Boolean { override fun isApplicableTo(element: JetStringTemplateExpression): Boolean {
if (element.getLastChild().getNode().getElementType() != JetTokens.CLOSING_QUOTE) return false // not available for unclosed literal if (element.getLastChild().getNode().getElementType() != JetTokens.CLOSING_QUOTE) return false // not available for unclosed literal
return element.getEntries().any { it is JetStringTemplateEntryWithExpression } return element.getEntries().any { it is JetStringTemplateEntryWithExpression }
@@ -34,46 +34,47 @@ public class ConvertToConcatenatedStringIntention : JetSelfTargetingOffsetIndepe
val quote = if (tripleQuoted) "\"\"\"" else "\"" val quote = if (tripleQuoted) "\"\"\"" else "\""
val entries = element.getEntries() val entries = element.getEntries()
val result = entries.sequence() val text = entries
.filterNot { it is JetStringTemplateEntryWithExpression && it.getExpression() == null }
.mapIndexed { index, entry -> .mapIndexed { index, entry ->
entry.toSeparateString(quote, convertExplicitly = index == 0, isFinalEntry = index == entries.size() - 1) entry.toSeparateString(quote, convertExplicitly = (index == 0), isFinalEntry = (index == entries.lastIndex))
} }
.join(separator = "+") .join(separator = "+")
.replaceAll("""$quote\+$quote""", "") .replaceAll("""$quote\+$quote""", "")
val replacement = JetPsiFactory(element).createExpression(result) val replacement = JetPsiFactory(element).createExpression(text)
element.replace(replacement) element.replace(replacement)
} }
private fun isTripleQuoted(str: String) = str.startsWith("\"\"\"") && str.endsWith("\"\"\"") private fun isTripleQuoted(str: String) = str.startsWith("\"\"\"") && str.endsWith("\"\"\"")
private fun JetStringTemplateEntry.toSeparateString(quote: String, convertExplicitly: Boolean, isFinalEntry: Boolean): String { private fun JetStringTemplateEntry.toSeparateString(quote: String, convertExplicitly: Boolean, isFinalEntry: Boolean): String {
if (this !is JetStringTemplateEntryWithExpression) return getText()!!.quote(quote) if (this !is JetStringTemplateEntryWithExpression) {
return getText().quote(quote)
val expression = getExpression()!!
val expressionText = if (needsParenthesis(expression, isFinalEntry)) "(${expression.getText()})" else expression.getText()!!
return if (convertExplicitly && !expression.isStringExpression()) {
expressionText + ".toString()"
}
else {
expressionText
} }
val expression = getExpression()!! // checked before
val text = if (needsParenthesis(expression, isFinalEntry))
"(" + expression.getText() + ")"
else
expression.getText()
return if (convertExplicitly && !expression.isStringExpression())
text + ".toString()"
else
text
} }
private fun needsParenthesis(expression: JetExpression, isFinalEntry: Boolean) = when (expression) { private fun needsParenthesis(expression: JetExpression, isFinalEntry: Boolean): Boolean {
is JetBinaryExpression -> true return when (expression) {
is JetIfExpression -> expression.getElse() !is JetBlockExpression && !isFinalEntry is JetBinaryExpression -> true
else -> false is JetIfExpression -> expression.getElse() !is JetBlockExpression && !isFinalEntry
else -> false
}
} }
private fun String.quote(quote: String) = quote + this + quote private fun String.quote(quote: String) = quote + this + quote
private fun JetExpression.isStringExpression(): Boolean { private fun JetExpression.isStringExpression() = KotlinBuiltIns.isString(BindingContextUtils.getRecordedTypeInfo(this, analyze())?.getType())
val context = this.analyze()
val elementType = BindingContextUtils.getRecordedTypeInfo(this, context)?.getType()
return KotlinBuiltIns.isString(elementType)
}
} }
@@ -0,0 +1 @@
val v = <caret>"${}saasd"
@@ -0,0 +1 @@
val v = "saasd"
@@ -3214,6 +3214,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("emptyBraces.kt")
public void testEmptyBraces() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertToConcatenatedStringIntention/emptyBraces.kt");
doTest(fileName);
}
@TestMetadata("handlesEscapeString.kt") @TestMetadata("handlesEscapeString.kt")
public void testHandlesEscapeString() throws Exception { public void testHandlesEscapeString() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertToConcatenatedStringIntention/handlesEscapeString.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertToConcatenatedStringIntention/handlesEscapeString.kt");