Merge pull request #826 from cypressious/catch_fixer

Implement smart enter processors for try, catch (parameters and body) and finally
This commit is contained in:
Dmitry Jemerov
2016-03-02 13:21:32 +01:00
7 changed files with 254 additions and 8 deletions
@@ -49,7 +49,12 @@ class KotlinSmartEnterHandler: SmartEnterProcessorWithFixers() {
KotlinFunctionDeclarationBodyFixer(),
KotlinPropertySetterParametersFixer(),
KotlinPropertySetterBodyFixer()
KotlinPropertySetterBodyFixer(),
KotlinTryBodyFixer(),
KotlinCatchParameterFixer(),
KotlinCatchBodyFixer(),
KotlinFinallyBodyFixer()
)
addEnterProcessors(KotlinPlainEnterProcessor())
@@ -0,0 +1,34 @@
/*
* 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.idea.editor.fixers
import com.intellij.lang.SmartEnterProcessorWithFixers
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.editor.KotlinSmartEnterHandler
import org.jetbrains.kotlin.psi.KtCatchClause
import org.jetbrains.kotlin.psi.psiUtil.endOffset
class KotlinCatchBodyFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSmartEnterHandler>() {
override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, psiElement: PsiElement) {
if (psiElement !is KtCatchClause) return
if (psiElement.catchBody == null) {
editor.document.insertString(psiElement.endOffset, "{}")
}
}
}
@@ -0,0 +1,45 @@
/*
* 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.idea.editor.fixers
import com.intellij.lang.SmartEnterProcessorWithFixers
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.editor.KotlinSmartEnterHandler
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtCatchClause
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
class KotlinCatchParameterFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSmartEnterHandler>() {
override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, psiElement: PsiElement) {
if (psiElement !is KtCatchClause) return
val catchEnd = psiElement.node.findChildByType(KtTokens.CATCH_KEYWORD)!!.textRange!!.endOffset
val parameterList = psiElement.parameterList
if (parameterList == null || parameterList.node.findChildByType(KtTokens.RPAR) == null) {
val endOffset = Math.min(psiElement.endOffset, psiElement.catchBody?.startOffset ?: Int.MAX_VALUE)
val parameter = parameterList?.parameters?.firstOrNull()?.text ?: ""
editor.document.replaceString(catchEnd, endOffset, "($parameter)")
processor.registerUnresolvedError(endOffset - 1)
}
else if (parameterList.parameters.firstOrNull()?.text.isNullOrBlank()) {
processor.registerUnresolvedError(parameterList.startOffset + 1)
}
}
}
@@ -0,0 +1,34 @@
/*
* 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.idea.editor.fixers
import com.intellij.lang.SmartEnterProcessorWithFixers
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.editor.KotlinSmartEnterHandler
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtFinallySection
class KotlinFinallyBodyFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSmartEnterHandler>() {
override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, psiElement: PsiElement) {
if (psiElement !is KtFinallySection) return
if (!psiElement.finalExpression.text.startsWith('{')) {
editor.document.insertString(psiElement.node.findChildByType(KtTokens.FINALLY_KEYWORD)!!.textRange.end, "{}")
}
}
}
@@ -17,11 +17,11 @@
package org.jetbrains.kotlin.idea.editor.fixers
import com.intellij.lang.SmartEnterProcessorWithFixers
import org.jetbrains.kotlin.idea.editor.KotlinSmartEnterHandler
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.idea.editor.KotlinSmartEnterHandler
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtIfExpression
class KotlinMissingIfBranchFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSmartEnterHandler>() {
override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, element: PsiElement) {
@@ -32,7 +32,7 @@ class KotlinMissingIfBranchFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSma
val elseKeyword = element.elseKeyword
if (elseKeyword != null) {
if (elseBranch == null || elseBranch !is KtBlockExpression && elseBranch.startLine(editor.document) > elseKeyword.startLine(editor.document)) {
if (elseBranch == null || elseBranch !is KtBlockExpression && elseBranch.startLine(document) > elseKeyword.startLine(document)) {
document.insertString(elseKeyword.range.end, "{}")
return
}
@@ -41,11 +41,10 @@ class KotlinMissingIfBranchFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSma
val thenBranch = element.then
if (thenBranch is KtBlockExpression) return
val rParen = element.rightParenthesis
if (rParen == null) return
val rParen = element.rightParenthesis ?: return
var transformingOneLiner = false
if (thenBranch != null && thenBranch.startLine(editor.document) == element.startLine(editor.document)) {
if (thenBranch != null && thenBranch.startLine(document) == element.startLine(document)) {
if (element.condition != null) return
transformingOneLiner = true
}
@@ -0,0 +1,35 @@
/*
* 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.idea.editor.fixers
import com.intellij.lang.SmartEnterProcessorWithFixers
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.editor.KotlinSmartEnterHandler
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtTryExpression
class KotlinTryBodyFixer : SmartEnterProcessorWithFixers.Fixer<KotlinSmartEnterHandler>() {
override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, psiElement: PsiElement) {
if (psiElement !is KtTryExpression) return
if (psiElement.tryBlock.lBrace == null) {
val offset = psiElement.node.findChildByType(KtTokens.TRY_KEYWORD)?.textRange?.endOffset ?: return
editor.document.insertString(offset, "{}")
}
}
}
@@ -1185,12 +1185,106 @@ class SmartEnterTest : KotlinLightCodeInsightFixtureTestCase() {
"""
)
fun testTryBody() = doFunTest(
"""
try<caret>
"""
,
"""
try {
<caret>
}
"""
)
fun testCatchBody() = doFunTest(
"""
try {
} catch(e: Exception) <caret>
"""
,
"""
try {
} catch(e: Exception) {
<caret>
}${" "}
"""
)
fun testCatchParameter1() = doFunTest(
"""
try {
} catch<caret>
"""
,
"""
try {
} catch(<caret>) {
}
"""
)
fun testCatchParameter2() = doFunTest(
"""
try {
} catch(<caret>
"""
,
"""
try {
} catch(<caret>) {
}
"""
)
fun testCatchParameter3() = doFunTest(
"""
try {
} catch(<caret> {}
"""
,
"""
try {
} catch(<caret>) {
}
"""
)
fun testCatchParameter4() = doFunTest(
"""
try {
} catch(e: Exception<caret>
"""
,
"""
try {
} catch(e: Exception) {
<caret>
}
"""
)
fun testFinallyBody() = doFunTest(
"""
try {
} catch(e: Exception) {
} finally<caret>
"""
,
"""
try {
} catch(e: Exception) {
} finally {
<caret>
}
"""
)
fun doFunTest(before: String, after: String) {
fun String.withFunContext(): String {
val bodyText = "//----\n${this.trimIndent()}\n//----"
val withIndent = bodyText.prependIndent(" ")
return "fun method() {\n${withIndent}\n}"
return "fun method() {\n$withIndent\n}"
}
doTest(before.withFunContext(), after.withFunContext())