From 60bc35b787a977e47f2daaa12b78a7b8d5e10fcf Mon Sep 17 00:00:00 2001 From: Vyacheslav Gerasimov Date: Mon, 7 Nov 2016 00:28:16 +0300 Subject: [PATCH] Implemented suppress lint intention action for android lint (KT-12020) #KT-12020 Fixed --- .../kotlin/generators/tests/GenerateTests.kt | 5 + .../AbstractAndroidIntentionTest.kt | 58 ++++++++++ .../AndroidIntentionTestGenerated.java | 101 +++++++++++++++++ .../IllegalIdentifier.html | 0 .../after.kt.template | 2 + .../before.kt.template | 1 + .../description.html | 5 + .../intentions/suppressLint/activityMethod.kt | 10 ++ .../suppressLint/activityMethod.kt.expected | 12 ++ .../suppressLint/addToExistingAnnotation.kt | 12 ++ .../addToExistingAnnotation.kt.expected | 12 ++ .../suppressLint/constructorParameter.kt | 4 + .../constructorParameter.kt.expected | 6 + .../suppressLint/destructuringDeclaration.kt | 9 ++ .../destructuringDeclaration.kt.expected | 12 ++ .../intentions/suppressLint/lambdaArgument.kt | 10 ++ .../suppressLint/lambdaArgument.kt.expected | 13 +++ .../suppressLint/lambdaArgumentProperty.kt | 6 + .../lambdaArgumentProperty.kt.expected | 9 ++ .../suppressLint/methodParameter.kt | 4 + .../suppressLint/methodParameter.kt.expected | 6 + .../suppressLint/propertyWithLambda.kt | 4 + .../propertyWithLambda.kt.expected | 7 ++ .../intentions/suppressLint/simpleProperty.kt | 4 + .../suppressLint/simpleProperty.kt.expected | 7 ++ plugins/lint/lint-idea/lint-idea.iml | 2 + .../klint/AndroidLintExternalAnnotator.java | 4 +- .../klint/SuppressLintIntentionAction.kt | 105 ++++++++++++++++++ 28 files changed, 427 insertions(+), 3 deletions(-) create mode 100644 idea/idea-android/tests/org/jetbrains/kotlin/android/intentions/AbstractAndroidIntentionTest.kt create mode 100644 idea/idea-android/tests/org/jetbrains/kotlin/android/intentions/AndroidIntentionTestGenerated.java rename idea/{idea-android/src => resources}/inspectionDescriptions/IllegalIdentifier.html (100%) create mode 100644 idea/resources/intentionDescriptions/SuppressLintIntentionAction/after.kt.template create mode 100644 idea/resources/intentionDescriptions/SuppressLintIntentionAction/before.kt.template create mode 100644 idea/resources/intentionDescriptions/SuppressLintIntentionAction/description.html create mode 100644 idea/testData/android/intentions/suppressLint/activityMethod.kt create mode 100644 idea/testData/android/intentions/suppressLint/activityMethod.kt.expected create mode 100644 idea/testData/android/intentions/suppressLint/addToExistingAnnotation.kt create mode 100644 idea/testData/android/intentions/suppressLint/addToExistingAnnotation.kt.expected create mode 100644 idea/testData/android/intentions/suppressLint/constructorParameter.kt create mode 100644 idea/testData/android/intentions/suppressLint/constructorParameter.kt.expected create mode 100644 idea/testData/android/intentions/suppressLint/destructuringDeclaration.kt create mode 100644 idea/testData/android/intentions/suppressLint/destructuringDeclaration.kt.expected create mode 100644 idea/testData/android/intentions/suppressLint/lambdaArgument.kt create mode 100644 idea/testData/android/intentions/suppressLint/lambdaArgument.kt.expected create mode 100644 idea/testData/android/intentions/suppressLint/lambdaArgumentProperty.kt create mode 100644 idea/testData/android/intentions/suppressLint/lambdaArgumentProperty.kt.expected create mode 100644 idea/testData/android/intentions/suppressLint/methodParameter.kt create mode 100644 idea/testData/android/intentions/suppressLint/methodParameter.kt.expected create mode 100644 idea/testData/android/intentions/suppressLint/propertyWithLambda.kt create mode 100644 idea/testData/android/intentions/suppressLint/propertyWithLambda.kt.expected create mode 100644 idea/testData/android/intentions/suppressLint/simpleProperty.kt create mode 100644 idea/testData/android/intentions/suppressLint/simpleProperty.kt.expected create mode 100644 plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/SuppressLintIntentionAction.kt diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index b62878a9425..05a9d612b26 100755 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.AbstractDataFlowValueRenderingTest import org.jetbrains.kotlin.addImport.AbstractAddImportTest import org.jetbrains.kotlin.android.* import org.jetbrains.kotlin.android.configure.AbstractConfigureProjectTest +import org.jetbrains.kotlin.android.intentions.AbstractAndroidIntentionTest import org.jetbrains.kotlin.android.intentions.AbstractAndroidResourceIntentionTest import org.jetbrains.kotlin.android.quickfixes.AbstractAndroidQuickFixMultiFileTest import org.jetbrains.kotlin.annotation.AbstractAnnotationProcessorBoxTest @@ -1161,6 +1162,10 @@ fun main(args: Array) { testClass() { model("android/lint", excludeParentDirs = true) } + + testClass() { + model("android/intentions", pattern = "^([\\w\\-_]+)\\.kt$") + } } testGroup("plugins/plugins-tests/tests", "plugins/android-extensions/android-extensions-jps/testData") { diff --git a/idea/idea-android/tests/org/jetbrains/kotlin/android/intentions/AbstractAndroidIntentionTest.kt b/idea/idea-android/tests/org/jetbrains/kotlin/android/intentions/AbstractAndroidIntentionTest.kt new file mode 100644 index 00000000000..95f51e33370 --- /dev/null +++ b/idea/idea-android/tests/org/jetbrains/kotlin/android/intentions/AbstractAndroidIntentionTest.kt @@ -0,0 +1,58 @@ +/* + * 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.android.intentions + +import com.android.SdkConstants +import com.intellij.openapi.util.io.FileUtil +import com.intellij.util.PathUtil +import org.jetbrains.android.inspections.klint.AndroidLintInspectionBase +import org.jetbrains.kotlin.android.KotlinAndroidTestCase +import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.test.InTextDirectivesUtils +import org.jetbrains.kotlin.test.KotlinTestUtils +import java.io.File + + +abstract class AbstractAndroidIntentionTest : KotlinAndroidTestCase() { + + fun doTest(path: String) { + val fileText = FileUtil.loadFile(File(path), true) + val intentionText = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// INTENTION_TEXT: ") ?: error("Empty intention text") + val mainInspectionClassName = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// INSPECTION_CLASS: ") ?: error("Empty inspection class name") + + val inspectionClass = Class.forName(mainInspectionClassName).newInstance() as AndroidLintInspectionBase + + myFixture.enableInspections(inspectionClass) + + val sourceFile = myFixture.copyFileToProject(path, "src/${PathUtil.getFileName(path)}") + myFixture.configureFromExistingVirtualFile(sourceFile) + + DirectiveBasedActionUtils.checkForUnexpectedErrors(myFixture.file as KtFile) + + val intention = myFixture.getAvailableIntention(intentionText) ?: error("Failed to find intention") + myFixture.launchAction(intention) + + myFixture.checkResultByFile(path + ".expected") + } + + override fun createManifest() { + myFixture.copyFileToProject("idea/testData/android/AndroidManifest.xml", SdkConstants.FN_ANDROID_MANIFEST_XML) + } + + override fun getTestDataPath() = KotlinTestUtils.getHomeDirectory() +} \ No newline at end of file diff --git a/idea/idea-android/tests/org/jetbrains/kotlin/android/intentions/AndroidIntentionTestGenerated.java b/idea/idea-android/tests/org/jetbrains/kotlin/android/intentions/AndroidIntentionTestGenerated.java new file mode 100644 index 00000000000..bb3ccfd8cd4 --- /dev/null +++ b/idea/idea-android/tests/org/jetbrains/kotlin/android/intentions/AndroidIntentionTestGenerated.java @@ -0,0 +1,101 @@ +/* + * 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.android.intentions; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("idea/testData/android/intentions") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class AndroidIntentionTestGenerated extends AbstractAndroidIntentionTest { + public void testAllFilesPresentInIntentions() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/android/intentions"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("idea/testData/android/intentions/suppressLint") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SuppressLint extends AbstractAndroidIntentionTest { + @TestMetadata("activityMethod.kt") + public void testActivityMethod() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intentions/suppressLint/activityMethod.kt"); + doTest(fileName); + } + + @TestMetadata("addToExistingAnnotation.kt") + public void testAddToExistingAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intentions/suppressLint/addToExistingAnnotation.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInSuppressLint() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/android/intentions/suppressLint"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("constructorParameter.kt") + public void testConstructorParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intentions/suppressLint/constructorParameter.kt"); + doTest(fileName); + } + + @TestMetadata("destructuringDeclaration.kt") + public void testDestructuringDeclaration() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intentions/suppressLint/destructuringDeclaration.kt"); + doTest(fileName); + } + + @TestMetadata("lambdaArgument.kt") + public void testLambdaArgument() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intentions/suppressLint/lambdaArgument.kt"); + doTest(fileName); + } + + @TestMetadata("lambdaArgumentProperty.kt") + public void testLambdaArgumentProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intentions/suppressLint/lambdaArgumentProperty.kt"); + doTest(fileName); + } + + @TestMetadata("methodParameter.kt") + public void testMethodParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intentions/suppressLint/methodParameter.kt"); + doTest(fileName); + } + + @TestMetadata("propertyWithLambda.kt") + public void testPropertyWithLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intentions/suppressLint/propertyWithLambda.kt"); + doTest(fileName); + } + + @TestMetadata("simpleProperty.kt") + public void testSimpleProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/intentions/suppressLint/simpleProperty.kt"); + doTest(fileName); + } + } +} diff --git a/idea/idea-android/src/inspectionDescriptions/IllegalIdentifier.html b/idea/resources/inspectionDescriptions/IllegalIdentifier.html similarity index 100% rename from idea/idea-android/src/inspectionDescriptions/IllegalIdentifier.html rename to idea/resources/inspectionDescriptions/IllegalIdentifier.html diff --git a/idea/resources/intentionDescriptions/SuppressLintIntentionAction/after.kt.template b/idea/resources/intentionDescriptions/SuppressLintIntentionAction/after.kt.template new file mode 100644 index 00000000000..d6e0483d822 --- /dev/null +++ b/idea/resources/intentionDescriptions/SuppressLintIntentionAction/after.kt.template @@ -0,0 +1,2 @@ +@SuppressLint("SdCardPath") +val a = "/sdcard" \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/SuppressLintIntentionAction/before.kt.template b/idea/resources/intentionDescriptions/SuppressLintIntentionAction/before.kt.template new file mode 100644 index 00000000000..24257c120aa --- /dev/null +++ b/idea/resources/intentionDescriptions/SuppressLintIntentionAction/before.kt.template @@ -0,0 +1 @@ +val a = "/sdcard" \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/SuppressLintIntentionAction/description.html b/idea/resources/intentionDescriptions/SuppressLintIntentionAction/description.html new file mode 100644 index 00000000000..20f0f81d326 --- /dev/null +++ b/idea/resources/intentionDescriptions/SuppressLintIntentionAction/description.html @@ -0,0 +1,5 @@ + + +This intention suppresses android lint warnings with @SuppressLint annotation added to closest parent declaration + + \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/activityMethod.kt b/idea/testData/android/intentions/suppressLint/activityMethod.kt new file mode 100644 index 00000000000..34cac7d0d3a --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/activityMethod.kt @@ -0,0 +1,10 @@ +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +import android.app.Activity +import android.os.Environment + + +class MainActivity : Activity() { + fun getSdCard(fromEnvironment: Boolean) = if (fromEnvironment) Environment.getExternalStorageDirectory().path else "/sdcard" +} \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/activityMethod.kt.expected b/idea/testData/android/intentions/suppressLint/activityMethod.kt.expected new file mode 100644 index 00000000000..846afb93f20 --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/activityMethod.kt.expected @@ -0,0 +1,12 @@ +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +import android.annotation.SuppressLint +import android.app.Activity +import android.os.Environment + + +class MainActivity : Activity() { + @SuppressLint("SdCardPath") + fun getSdCard(fromEnvironment: Boolean) = if (fromEnvironment) Environment.getExternalStorageDirectory().path else "/sdcard" +} \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/addToExistingAnnotation.kt b/idea/testData/android/intentions/suppressLint/addToExistingAnnotation.kt new file mode 100644 index 00000000000..a0a917d5854 --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/addToExistingAnnotation.kt @@ -0,0 +1,12 @@ +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +import android.annotation.SuppressLint +import android.app.Activity +import android.os.Environment + + +class MainActivity : Activity() { + @SuppressLint("Something") + fun getSdCard(fromEnvironment: Boolean) = if (fromEnvironment) Environment.getExternalStorageDirectory().path else "/sdcard" +} \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/addToExistingAnnotation.kt.expected b/idea/testData/android/intentions/suppressLint/addToExistingAnnotation.kt.expected new file mode 100644 index 00000000000..c434eea2f1e --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/addToExistingAnnotation.kt.expected @@ -0,0 +1,12 @@ +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +import android.annotation.SuppressLint +import android.app.Activity +import android.os.Environment + + +class MainActivity : Activity() { + @SuppressLint("Something", "SdCardPath") + fun getSdCard(fromEnvironment: Boolean) = if (fromEnvironment) Environment.getExternalStorageDirectory().path else "/sdcard" +} \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/constructorParameter.kt b/idea/testData/android/intentions/suppressLint/constructorParameter.kt new file mode 100644 index 00000000000..bfed3b9be56 --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/constructorParameter.kt @@ -0,0 +1,4 @@ +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +class SdCard(val path: String = "/sdcard") \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/constructorParameter.kt.expected b/idea/testData/android/intentions/suppressLint/constructorParameter.kt.expected new file mode 100644 index 00000000000..68149e8eef5 --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/constructorParameter.kt.expected @@ -0,0 +1,6 @@ +import android.annotation.SuppressLint + +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +class SdCard(@SuppressLint("SdCardPath") val path: String = "/sdcard") \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/destructuringDeclaration.kt b/idea/testData/android/intentions/suppressLint/destructuringDeclaration.kt new file mode 100644 index 00000000000..346336db2f8 --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/destructuringDeclaration.kt @@ -0,0 +1,9 @@ +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +fun foo() { + val (a: String, b: String) = "/sdcard" +} + +operator fun CharSequence.component1(): String = "component1" +operator fun CharSequence.component2(): String = "component2" diff --git a/idea/testData/android/intentions/suppressLint/destructuringDeclaration.kt.expected b/idea/testData/android/intentions/suppressLint/destructuringDeclaration.kt.expected new file mode 100644 index 00000000000..52c9012bfb0 --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/destructuringDeclaration.kt.expected @@ -0,0 +1,12 @@ +import android.annotation.SuppressLint + +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +@SuppressLint("SdCardPath") +fun foo() { + val (a: String, b: String) = "/sdcard" +} + +operator fun CharSequence.component1(): String = "component1" +operator fun CharSequence.component2(): String = "component2" diff --git a/idea/testData/android/intentions/suppressLint/lambdaArgument.kt b/idea/testData/android/intentions/suppressLint/lambdaArgument.kt new file mode 100644 index 00000000000..08556f1ec6c --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/lambdaArgument.kt @@ -0,0 +1,10 @@ +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +fun foo(l: Any) = l + +fun bar() { + foo() { + "/sdcard" + } +} \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/lambdaArgument.kt.expected b/idea/testData/android/intentions/suppressLint/lambdaArgument.kt.expected new file mode 100644 index 00000000000..34e862ad244 --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/lambdaArgument.kt.expected @@ -0,0 +1,13 @@ +import android.annotation.SuppressLint + +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +fun foo(l: Any) = l + +@SuppressLint("SdCardPath") +fun bar() { + foo() { + "/sdcard" + } +} \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/lambdaArgumentProperty.kt b/idea/testData/android/intentions/suppressLint/lambdaArgumentProperty.kt new file mode 100644 index 00000000000..233767c23ce --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/lambdaArgumentProperty.kt @@ -0,0 +1,6 @@ +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +fun foo(l: Any) = l + +val bar = foo() { "/sdcard" } \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/lambdaArgumentProperty.kt.expected b/idea/testData/android/intentions/suppressLint/lambdaArgumentProperty.kt.expected new file mode 100644 index 00000000000..575e18d9392 --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/lambdaArgumentProperty.kt.expected @@ -0,0 +1,9 @@ +import android.annotation.SuppressLint + +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +fun foo(l: Any) = l + +@SuppressLint("SdCardPath") +val bar = foo() { "/sdcard" } \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/methodParameter.kt b/idea/testData/android/intentions/suppressLint/methodParameter.kt new file mode 100644 index 00000000000..854638e52c2 --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/methodParameter.kt @@ -0,0 +1,4 @@ +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +fun foo(path: String = "/sdcard") = path \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/methodParameter.kt.expected b/idea/testData/android/intentions/suppressLint/methodParameter.kt.expected new file mode 100644 index 00000000000..481ddf3fff0 --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/methodParameter.kt.expected @@ -0,0 +1,6 @@ +import android.annotation.SuppressLint + +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +fun foo(@SuppressLint("SdCardPath") path: String = "/sdcard") = path \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/propertyWithLambda.kt b/idea/testData/android/intentions/suppressLint/propertyWithLambda.kt new file mode 100644 index 00000000000..8afada5c2d6 --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/propertyWithLambda.kt @@ -0,0 +1,4 @@ +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +val getPath = { "/sdcard" } \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/propertyWithLambda.kt.expected b/idea/testData/android/intentions/suppressLint/propertyWithLambda.kt.expected new file mode 100644 index 00000000000..65e05d26d97 --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/propertyWithLambda.kt.expected @@ -0,0 +1,7 @@ +import android.annotation.SuppressLint + +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +@SuppressLint("SdCardPath") +val getPath = { "/sdcard" } \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/simpleProperty.kt b/idea/testData/android/intentions/suppressLint/simpleProperty.kt new file mode 100644 index 00000000000..c4fee12198d --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/simpleProperty.kt @@ -0,0 +1,4 @@ +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +val path = "/sdcard" \ No newline at end of file diff --git a/idea/testData/android/intentions/suppressLint/simpleProperty.kt.expected b/idea/testData/android/intentions/suppressLint/simpleProperty.kt.expected new file mode 100644 index 00000000000..1b00a0a7951 --- /dev/null +++ b/idea/testData/android/intentions/suppressLint/simpleProperty.kt.expected @@ -0,0 +1,7 @@ +import android.annotation.SuppressLint + +// INTENTION_TEXT: Suppress: Add @SuppressLint("SdCardPath") annotation +// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection + +@SuppressLint("SdCardPath") +val path = "/sdcard" \ No newline at end of file diff --git a/plugins/lint/lint-idea/lint-idea.iml b/plugins/lint/lint-idea/lint-idea.iml index da20043eccd..fe3d0017a80 100644 --- a/plugins/lint/lint-idea/lint-idea.iml +++ b/plugins/lint/lint-idea/lint-idea.iml @@ -16,5 +16,7 @@ + + \ No newline at end of file diff --git a/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AndroidLintExternalAnnotator.java b/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AndroidLintExternalAnnotator.java index 0ea9c3767be..b244a9c1953 100644 --- a/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AndroidLintExternalAnnotator.java +++ b/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AndroidLintExternalAnnotator.java @@ -1,13 +1,10 @@ package org.jetbrains.android.inspections.klint; -import com.android.SdkConstants; -import com.android.tools.idea.gradle.util.Projects; import com.android.tools.klint.client.api.IssueRegistry; import com.android.tools.klint.client.api.LintDriver; import com.android.tools.klint.client.api.LintRequest; import com.android.tools.klint.detector.api.Issue; import com.android.tools.klint.detector.api.Scope; -import com.android.utils.SdkUtils; import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.DaemonBundle; @@ -248,6 +245,7 @@ public class AndroidLintExternalAnnotator extends ExternalAnnotator annotationContainer.addAnnotation( + FQNAME_SUPPRESS_LINT, + argument, + whiteSpaceText = if (annotationContainer.isNewLineNeededForAnnotation()) "\n" else " ", + addToExistingAnnotation = { entry -> addArgumentToAnnotation(entry, argument) }) + } + } + + private fun addArgumentToAnnotation(entry: KtAnnotationEntry, argument: String): Boolean { + // add new arguments to an existing entry + val args = entry.valueArgumentList + val psiFactory = KtPsiFactory(entry) + val newArgList = psiFactory.createCallArguments("($argument)") + if (args == null) { + // new argument list + entry.addAfter(newArgList, entry.lastChild) + } + else if (args.arguments.isEmpty()) { + // replace '()' with a new argument list + args.replace(newArgList) + } + else if (args.arguments.none { it.textMatches(argument) }) { + args.addArgument(newArgList.arguments[0]) + } + + return true + } + + private fun getLintId(intentionId: String) = + if (intentionId.startsWith(INTENTION_NAME_PREFIX)) intentionId.substring(INTENTION_NAME_PREFIX.length) else intentionId + + private fun KtElement.isNewLineNeededForAnnotation() = !(this is KtParameter || this is KtTypeParameter) + + private fun PsiElement.isSuppressLintTarget() = this is KtDeclaration && + this !is KtDestructuringDeclaration && + this !is KtFunctionLiteral +} \ No newline at end of file