From 15bfd4439ac15cfbbe771ed54e0d91e9e36849f2 Mon Sep 17 00:00:00 2001 From: Vyacheslav Gerasimov Date: Tue, 30 May 2017 15:32:13 +0300 Subject: [PATCH] Fix AddTargetVersionCheckQuickFix, generate else branch with TODO when surrounded statement used as expression #KT-17786 Fixed #KT-17788 Fixed --- .../AndroidLintQuickfixTestGenerated.java | 12 ++++++++ .../destructuringDeclaration.kt | 12 ++++++++ .../destructuringDeclaration.kt.expected | 17 +++++++++++ .../expressionBody.kt.expected | 2 ++ .../functionLiteral.kt.expected | 6 ++-- .../getterWIthExpressionBody.kt | 7 +++++ .../getterWIthExpressionBody.kt.expected | 12 ++++++++ .../targetVersionCheck/if.kt.expected | 6 ++-- .../ifWithBlock.kt.expected | 6 ++-- .../inlinedConstant.kt.expected | 6 ++-- .../targetVersionCheck/method.kt.expected | 6 ++-- .../targetVersionCheck/when.kt.expected | 2 ++ .../klint/AddTargetVersionCheckQuickFix.kt | 30 ++++++++++++++----- 13 files changed, 106 insertions(+), 18 deletions(-) create mode 100644 idea/testData/android/lintQuickfix/targetVersionCheck/destructuringDeclaration.kt create mode 100644 idea/testData/android/lintQuickfix/targetVersionCheck/destructuringDeclaration.kt.expected create mode 100644 idea/testData/android/lintQuickfix/targetVersionCheck/getterWIthExpressionBody.kt create mode 100644 idea/testData/android/lintQuickfix/targetVersionCheck/getterWIthExpressionBody.kt.expected diff --git a/idea/idea-android/tests/org/jetbrains/kotlin/android/quickfix/AndroidLintQuickfixTestGenerated.java b/idea/idea-android/tests/org/jetbrains/kotlin/android/quickfix/AndroidLintQuickfixTestGenerated.java index 059a35ef6f4..bc41d2eb35a 100644 --- a/idea/idea-android/tests/org/jetbrains/kotlin/android/quickfix/AndroidLintQuickfixTestGenerated.java +++ b/idea/idea-android/tests/org/jetbrains/kotlin/android/quickfix/AndroidLintQuickfixTestGenerated.java @@ -278,6 +278,12 @@ public class AndroidLintQuickfixTestGenerated extends AbstractAndroidLintQuickfi 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") public void testExpressionBody() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/lintQuickfix/targetVersionCheck/expressionBody.kt"); @@ -290,6 +296,12 @@ public class AndroidLintQuickfixTestGenerated extends AbstractAndroidLintQuickfi 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") public void testIf() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/lintQuickfix/targetVersionCheck/if.kt"); diff --git a/idea/testData/android/lintQuickfix/targetVersionCheck/destructuringDeclaration.kt b/idea/testData/android/lintQuickfix/targetVersionCheck/destructuringDeclaration.kt new file mode 100644 index 00000000000..8aee1d9d670 --- /dev/null +++ b/idea/testData/android/lintQuickfix/targetVersionCheck/destructuringDeclaration.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(VectorDrawable(), 0) +} \ No newline at end of file diff --git a/idea/testData/android/lintQuickfix/targetVersionCheck/destructuringDeclaration.kt.expected b/idea/testData/android/lintQuickfix/targetVersionCheck/destructuringDeclaration.kt.expected new file mode 100644 index 00000000000..dd2eb2154bc --- /dev/null +++ b/idea/testData/android/lintQuickfix/targetVersionCheck/destructuringDeclaration.kt.expected @@ -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") + } +} \ No newline at end of file diff --git a/idea/testData/android/lintQuickfix/targetVersionCheck/expressionBody.kt.expected b/idea/testData/android/lintQuickfix/targetVersionCheck/expressionBody.kt.expected index 4dbd098d280..878163aab0f 100644 --- a/idea/testData/android/lintQuickfix/targetVersionCheck/expressionBody.kt.expected +++ b/idea/testData/android/lintQuickfix/targetVersionCheck/expressionBody.kt.expected @@ -7,5 +7,7 @@ import android.os.Build class VectorDrawableProvider { fun getVectorDrawable(): VectorDrawable = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { VectorDrawable() + } else { + TODO("VERSION.SDK_INT < LOLLIPOP") } } \ No newline at end of file diff --git a/idea/testData/android/lintQuickfix/targetVersionCheck/functionLiteral.kt.expected b/idea/testData/android/lintQuickfix/targetVersionCheck/functionLiteral.kt.expected index 375c7905f46..a6165526117 100644 --- a/idea/testData/android/lintQuickfix/targetVersionCheck/functionLiteral.kt.expected +++ b/idea/testData/android/lintQuickfix/targetVersionCheck/functionLiteral.kt.expected @@ -7,8 +7,10 @@ import android.os.Build class VectorDrawableProvider { fun getVectorDrawable(): VectorDrawable { with(this) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return VectorDrawable() + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + VectorDrawable() + } else { + TODO("VERSION.SDK_INT < LOLLIPOP") } } } diff --git a/idea/testData/android/lintQuickfix/targetVersionCheck/getterWIthExpressionBody.kt b/idea/testData/android/lintQuickfix/targetVersionCheck/getterWIthExpressionBody.kt new file mode 100644 index 00000000000..79651954230 --- /dev/null +++ b/idea/testData/android/lintQuickfix/targetVersionCheck/getterWIthExpressionBody.kt @@ -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() = VectorDrawable() \ No newline at end of file diff --git a/idea/testData/android/lintQuickfix/targetVersionCheck/getterWIthExpressionBody.kt.expected b/idea/testData/android/lintQuickfix/targetVersionCheck/getterWIthExpressionBody.kt.expected new file mode 100644 index 00000000000..01d2adcc812 --- /dev/null +++ b/idea/testData/android/lintQuickfix/targetVersionCheck/getterWIthExpressionBody.kt.expected @@ -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") + } \ No newline at end of file diff --git a/idea/testData/android/lintQuickfix/targetVersionCheck/if.kt.expected b/idea/testData/android/lintQuickfix/targetVersionCheck/if.kt.expected index c1fe66e6c43..960340e8eca 100644 --- a/idea/testData/android/lintQuickfix/targetVersionCheck/if.kt.expected +++ b/idea/testData/android/lintQuickfix/targetVersionCheck/if.kt.expected @@ -8,8 +8,10 @@ class VectorDrawableProvider { val flag = false fun getVectorDrawable(): VectorDrawable { if (flag) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return VectorDrawable() + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + VectorDrawable() + } else { + TODO("VERSION.SDK_INT < LOLLIPOP") } } } \ No newline at end of file diff --git a/idea/testData/android/lintQuickfix/targetVersionCheck/ifWithBlock.kt.expected b/idea/testData/android/lintQuickfix/targetVersionCheck/ifWithBlock.kt.expected index bb365b9d6f9..224a8f295f8 100644 --- a/idea/testData/android/lintQuickfix/targetVersionCheck/ifWithBlock.kt.expected +++ b/idea/testData/android/lintQuickfix/targetVersionCheck/ifWithBlock.kt.expected @@ -8,8 +8,10 @@ class VectorDrawableProvider { val flag = false fun getVectorDrawable(): VectorDrawable { if (flag) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return VectorDrawable() + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + VectorDrawable() + } else { + TODO("VERSION.SDK_INT < LOLLIPOP") } } } diff --git a/idea/testData/android/lintQuickfix/targetVersionCheck/inlinedConstant.kt.expected b/idea/testData/android/lintQuickfix/targetVersionCheck/inlinedConstant.kt.expected index 0634eeb5fe6..80f478a30d7 100644 --- a/idea/testData/android/lintQuickfix/targetVersionCheck/inlinedConstant.kt.expected +++ b/idea/testData/android/lintQuickfix/targetVersionCheck/inlinedConstant.kt.expected @@ -5,8 +5,10 @@ import android.os.Build class Test { fun foo(): Int { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - return android.R.attr.windowTranslucentStatus + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + android.R.attr.windowTranslucentStatus + } else { + TODO("VERSION.SDK_INT < KITKAT") } } } \ No newline at end of file diff --git a/idea/testData/android/lintQuickfix/targetVersionCheck/method.kt.expected b/idea/testData/android/lintQuickfix/targetVersionCheck/method.kt.expected index 20a4c2038f5..6685b74c231 100644 --- a/idea/testData/android/lintQuickfix/targetVersionCheck/method.kt.expected +++ b/idea/testData/android/lintQuickfix/targetVersionCheck/method.kt.expected @@ -6,8 +6,10 @@ import android.os.Build class VectorDrawableProvider { fun getVectorDrawable(): VectorDrawable { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return VectorDrawable() + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + VectorDrawable() + } else { + TODO("VERSION.SDK_INT < LOLLIPOP") } } } \ No newline at end of file diff --git a/idea/testData/android/lintQuickfix/targetVersionCheck/when.kt.expected b/idea/testData/android/lintQuickfix/targetVersionCheck/when.kt.expected index 90ccdff38f1..bfe5397edec 100644 --- a/idea/testData/android/lintQuickfix/targetVersionCheck/when.kt.expected +++ b/idea/testData/android/lintQuickfix/targetVersionCheck/when.kt.expected @@ -10,6 +10,8 @@ class VectorDrawableProvider { return when (flag) { true -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { VectorDrawable() + } else { + TODO("VERSION.SDK_INT < LOLLIPOP") } else -> VectorDrawable() } diff --git a/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AddTargetVersionCheckQuickFix.kt b/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AddTargetVersionCheckQuickFix.kt index e38cfcba535..347a402f1b1 100644 --- a/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AddTargetVersionCheckQuickFix.kt +++ b/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AddTargetVersionCheckQuickFix.kt @@ -20,18 +20,17 @@ import com.intellij.codeInsight.FileModificationService import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement 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.core.ShortenReferences import org.jetbrains.kotlin.idea.inspections.findExistingEditor import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode class AddTargetVersionCheckQuickFix(val api: Int) : AndroidLintQuickFix { - companion object { - private val IF_SURROUNDER = KotlinIfSurrounder() - } - override fun apply(startElement: PsiElement, endElement: PsiElement, context: AndroidQuickfixContexts.Context) { val targetExpression = getTargetExpression(startElement) val project = targetExpression?.project ?: return @@ -45,7 +44,8 @@ class AddTargetVersionCheckQuickFix(val api: Int) : AndroidLintQuickFix { 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)}" document.replaceString(conditionRange.startOffset, conditionRange.endOffset, conditionText) 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)}) { ... }" - // TODO: Delegated property, initializer, annotation parameter - private fun getTargetExpression(element: PsiElement): PsiElement? { + private fun getTargetExpression(element: PsiElement): KtElement? { var current = PsiTreeUtil.getParentOfType(element, KtExpression::class.java) while (current != null) { if (current.parent is KtBlockExpression || current.parent is KtContainerNode || 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 } current = PsiTreeUtil.getParentOfType(current, KtExpression::class.java, true) @@ -75,4 +78,15 @@ class AddTargetVersionCheckQuickFix(val api: Int) : AndroidLintQuickFix { 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() + } + } } \ No newline at end of file