Fix AddTargetVersionCheckQuickFix, generate else branch with TODO

when surrounded statement used as expression

#KT-17786 Fixed
#KT-17788 Fixed
This commit is contained in:
Vyacheslav Gerasimov
2017-05-30 15:32:13 +03:00
parent 33c3ba815f
commit 15bfd4439a
13 changed files with 106 additions and 18 deletions
@@ -278,6 +278,12 @@ public class AndroidLintQuickfixTestGenerated extends AbstractAndroidLintQuickfi
doTest(fileName); doTest(fileName);
} }
@TestMetadata("destructuringDeclaration.kt")
public void testDestructuringDeclaration() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/lintQuickfix/targetVersionCheck/destructuringDeclaration.kt");
doTest(fileName);
}
@TestMetadata("expressionBody.kt") @TestMetadata("expressionBody.kt")
public void testExpressionBody() throws Exception { public void testExpressionBody() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/lintQuickfix/targetVersionCheck/expressionBody.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/lintQuickfix/targetVersionCheck/expressionBody.kt");
@@ -290,6 +296,12 @@ public class AndroidLintQuickfixTestGenerated extends AbstractAndroidLintQuickfi
doTest(fileName); doTest(fileName);
} }
@TestMetadata("getterWIthExpressionBody.kt")
public void testGetterWIthExpressionBody() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/lintQuickfix/targetVersionCheck/getterWIthExpressionBody.kt");
doTest(fileName);
}
@TestMetadata("if.kt") @TestMetadata("if.kt")
public void testIf() throws Exception { public void testIf() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/lintQuickfix/targetVersionCheck/if.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/lintQuickfix/targetVersionCheck/if.kt");
@@ -0,0 +1,12 @@
// INTENTION_TEXT: Surround with if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { ... }
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection
import android.app.Activity
import android.graphics.drawable.VectorDrawable
data class ValueProvider(var p1: VectorDrawable, val p2: Int)
val activity = Activity()
fun foo() {
val (v1, v2) = ValueProvider(<caret>VectorDrawable(), 0)
}
@@ -0,0 +1,17 @@
// INTENTION_TEXT: Surround with if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { ... }
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection
import android.app.Activity
import android.graphics.drawable.VectorDrawable
import android.os.Build
data class ValueProvider(var p1: VectorDrawable, val p2: Int)
val activity = Activity()
fun foo() {
val (v1, v2) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ValueProvider(VectorDrawable(), 0)
} else {
TODO("VERSION.SDK_INT < LOLLIPOP")
}
}
@@ -7,5 +7,7 @@ import android.os.Build
class VectorDrawableProvider { class VectorDrawableProvider {
fun getVectorDrawable(): VectorDrawable = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { fun getVectorDrawable(): VectorDrawable = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
VectorDrawable() VectorDrawable()
} else {
TODO("VERSION.SDK_INT < LOLLIPOP")
} }
} }
@@ -7,8 +7,10 @@ import android.os.Build
class VectorDrawableProvider { class VectorDrawableProvider {
fun getVectorDrawable(): VectorDrawable { fun getVectorDrawable(): VectorDrawable {
with(this) { with(this) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return VectorDrawable() VectorDrawable()
} else {
TODO("VERSION.SDK_INT < LOLLIPOP")
} }
} }
} }
@@ -0,0 +1,7 @@
// INTENTION_TEXT: Surround with if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { ... }
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection
import android.graphics.drawable.VectorDrawable
val v: VectorDrawable
get() = <caret>VectorDrawable()
@@ -0,0 +1,12 @@
// INTENTION_TEXT: Surround with if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { ... }
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection
import android.graphics.drawable.VectorDrawable
import android.os.Build
val v: VectorDrawable
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
VectorDrawable()
} else {
TODO("VERSION.SDK_INT < LOLLIPOP")
}
@@ -8,8 +8,10 @@ class VectorDrawableProvider {
val flag = false val flag = false
fun getVectorDrawable(): VectorDrawable { fun getVectorDrawable(): VectorDrawable {
if (flag) if (flag)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return VectorDrawable() VectorDrawable()
} else {
TODO("VERSION.SDK_INT < LOLLIPOP")
} }
} }
} }
@@ -8,8 +8,10 @@ class VectorDrawableProvider {
val flag = false val flag = false
fun getVectorDrawable(): VectorDrawable { fun getVectorDrawable(): VectorDrawable {
if (flag) { if (flag) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return VectorDrawable() VectorDrawable()
} else {
TODO("VERSION.SDK_INT < LOLLIPOP")
} }
} }
} }
@@ -5,8 +5,10 @@ import android.os.Build
class Test { class Test {
fun foo(): Int { fun foo(): Int {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
return android.R.attr.windowTranslucentStatus android.R.attr.windowTranslucentStatus
} else {
TODO("VERSION.SDK_INT < KITKAT")
} }
} }
} }
@@ -6,8 +6,10 @@ import android.os.Build
class VectorDrawableProvider { class VectorDrawableProvider {
fun getVectorDrawable(): VectorDrawable { fun getVectorDrawable(): VectorDrawable {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return VectorDrawable() VectorDrawable()
} else {
TODO("VERSION.SDK_INT < LOLLIPOP")
} }
} }
} }
@@ -10,6 +10,8 @@ class VectorDrawableProvider {
return when (flag) { return when (flag) {
true -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { true -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
VectorDrawable() VectorDrawable()
} else {
TODO("VERSION.SDK_INT < LOLLIPOP")
} }
else -> VectorDrawable() else -> VectorDrawable()
} }
@@ -20,18 +20,17 @@ import com.intellij.codeInsight.FileModificationService
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.codeInsight.surroundWith.statement.KotlinIfSurrounder import org.jetbrains.kotlin.idea.codeInsight.surroundWith.statement.KotlinIfSurrounder
import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.inspections.findExistingEditor import org.jetbrains.kotlin.idea.inspections.findExistingEditor
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class AddTargetVersionCheckQuickFix(val api: Int) : AndroidLintQuickFix { class AddTargetVersionCheckQuickFix(val api: Int) : AndroidLintQuickFix {
companion object {
private val IF_SURROUNDER = KotlinIfSurrounder()
}
override fun apply(startElement: PsiElement, endElement: PsiElement, context: AndroidQuickfixContexts.Context) { override fun apply(startElement: PsiElement, endElement: PsiElement, context: AndroidQuickfixContexts.Context) {
val targetExpression = getTargetExpression(startElement) val targetExpression = getTargetExpression(startElement)
val project = targetExpression?.project ?: return val project = targetExpression?.project ?: return
@@ -45,7 +44,8 @@ class AddTargetVersionCheckQuickFix(val api: Int) : AndroidLintQuickFix {
return return
} }
val conditionRange = IF_SURROUNDER.surroundElements(project, editor, arrayOf(targetExpression)) ?: return val surrounder = getSurrounder(targetExpression, "\"VERSION.SDK_INT < ${getVersionField(api, false)}\"")
val conditionRange = surrounder.surroundElements(project, editor, arrayOf(targetExpression)) ?: return
val conditionText = "android.os.Build.VERSION.SDK_INT >= ${getVersionField(api, true)}" val conditionText = "android.os.Build.VERSION.SDK_INT >= ${getVersionField(api, true)}"
document.replaceString(conditionRange.startOffset, conditionRange.endOffset, conditionText) document.replaceString(conditionRange.startOffset, conditionRange.endOffset, conditionText)
documentManager.commitDocument(document) documentManager.commitDocument(document)
@@ -60,14 +60,17 @@ class AddTargetVersionCheckQuickFix(val api: Int) : AndroidLintQuickFix {
override fun getName(): String = "Surround with if (VERSION.SDK_INT >= VERSION_CODES.${getVersionField(api, false)}) { ... }" override fun getName(): String = "Surround with if (VERSION.SDK_INT >= VERSION_CODES.${getVersionField(api, false)}) { ... }"
// TODO: Delegated property, initializer, annotation parameter private fun getTargetExpression(element: PsiElement): KtElement? {
private fun getTargetExpression(element: PsiElement): PsiElement? {
var current = PsiTreeUtil.getParentOfType(element, KtExpression::class.java) var current = PsiTreeUtil.getParentOfType(element, KtExpression::class.java)
while (current != null) { while (current != null) {
if (current.parent is KtBlockExpression || if (current.parent is KtBlockExpression ||
current.parent is KtContainerNode || current.parent is KtContainerNode ||
current.parent is KtWhenEntry || current.parent is KtWhenEntry ||
current.parent is KtFunction) { current.parent is KtFunction ||
current.parent is KtPropertyAccessor ||
current.parent is KtProperty ||
current.parent is KtReturnExpression ||
current.parent is KtDestructuringDeclaration) {
break break
} }
current = PsiTreeUtil.getParentOfType(current, KtExpression::class.java, true) current = PsiTreeUtil.getParentOfType(current, KtExpression::class.java, true)
@@ -75,4 +78,15 @@ class AddTargetVersionCheckQuickFix(val api: Int) : AndroidLintQuickFix {
return current return current
} }
private fun getSurrounder(element: KtElement, todoText: String?): KotlinIfSurrounder {
val used = element.analyze(BodyResolveMode.PARTIAL)[BindingContext.USED_AS_EXPRESSION, element] ?: false
return if (used) {
object : KotlinIfSurrounder() {
override fun getCodeTemplate(): String = "if (a) { \n} else {\nTODO(${todoText ?: ""})\n}"
}
} else {
KotlinIfSurrounder()
}
}
} }