diff --git a/generators/generators.iml b/generators/generators.iml
index b6db11cc352..1406adca488 100644
--- a/generators/generators.iml
+++ b/generators/generators.iml
@@ -35,5 +35,6 @@
+
\ No newline at end of file
diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt
index 862ddc7661e..5e0e608cf1b 100644
--- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt
+++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt
@@ -19,10 +19,7 @@ package org.jetbrains.kotlin.generators.tests
import junit.framework.TestCase
import org.jetbrains.kotlin.AbstractDataFlowValueRenderingTest
import org.jetbrains.kotlin.addImport.AbstractAddImportTest
-import org.jetbrains.kotlin.android.AbstractAndroidCompletionTest
-import org.jetbrains.kotlin.android.AbstractAndroidFindUsagesTest
-import org.jetbrains.kotlin.android.AbstractAndroidGotoTest
-import org.jetbrains.kotlin.android.AbstractAndroidRenameTest
+import org.jetbrains.kotlin.android.*
import org.jetbrains.kotlin.android.configure.AbstractConfigureProjectTest
import org.jetbrains.kotlin.annotation.AbstractAnnotationProcessorBoxTest
import org.jetbrains.kotlin.asJava.AbstractCompilerLightClassTest
@@ -136,6 +133,7 @@ import org.jetbrains.kotlin.resolve.constraintSystem.AbstractConstraintSystemTes
import org.jetbrains.kotlin.serialization.AbstractLocalClassProtoTest
import org.jetbrains.kotlin.shortenRefs.AbstractShortenRefsTest
import org.jetbrains.kotlin.types.AbstractTypeBindingTest
+import org.jetbrains.kotlin.uast.AbstractKotlinLintTest
import java.io.File
import java.util.*
import java.util.regex.Pattern
@@ -975,6 +973,12 @@ fun main(args: Array) {
}
}
+ testGroup("plugins/uast-kotlin/test", "plugins/uast-kotlin/testData") {
+ testClass() {
+ model("lint", excludeParentDirs = true)
+ }
+ }
+
testGroup("plugins/plugins-tests/tests", "plugins/annotation-collector/testData") {
testClass() {
model("collectToFile", recursive = false, extension = null)
diff --git a/plugins/uast-kotlin/test/org.jetbrains.kotlin.uast/AbstractKotlinLintTest.kt b/plugins/uast-kotlin/test/org.jetbrains.kotlin.uast/AbstractKotlinLintTest.kt
new file mode 100644
index 00000000000..e2dff1216b0
--- /dev/null
+++ b/plugins/uast-kotlin/test/org.jetbrains.kotlin.uast/AbstractKotlinLintTest.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.uast
+
+import org.jetbrains.android.inspections.klint.AndroidLintInspectionBase
+import org.jetbrains.kotlin.android.KotlinAndroidTestCase
+import org.jetbrains.kotlin.test.InTextDirectivesUtils.findStringWithPrefixes
+import org.jetbrains.kotlin.test.KotlinTestUtils
+import java.io.File
+
+abstract class AbstractKotlinLintTest : KotlinAndroidTestCase() {
+
+ override fun setUp() {
+ super.setUp()
+ AndroidLintInspectionBase.invalidateInspectionShortName2IssueMap()
+ }
+
+ fun doTest(filename: String) {
+ val ktFile = File(filename)
+ val mainInspectionClassName = findStringWithPrefixes(ktFile.readText(), "// INSPECTION_CLASS: ") ?: error("Empty class name")
+
+ val inspectionClassNames = mutableListOf(mainInspectionClassName)
+ for (i in 2..100) {
+ val className = findStringWithPrefixes(ktFile.readText(), "// INSPECTION_CLASS$i: ") ?: break
+ inspectionClassNames += className
+ }
+
+ myFixture.enableInspections(*inspectionClassNames.map { className ->
+ val inspectionClass = Class.forName(className)
+ inspectionClass.newInstance() as AndroidLintInspectionBase
+ }.toTypedArray())
+
+ val additionalResourcesDir = File(ktFile.parentFile, getTestName(true))
+ if (additionalResourcesDir.exists()) {
+ for (file in additionalResourcesDir.listFiles()) {
+ if (file.isFile) {
+ myFixture.copyFileToProject(file.absolutePath, file.name)
+ }
+ else if (file.isDirectory) {
+ myFixture.copyDirectoryToProject(file.absolutePath, file.name)
+ }
+ }
+ }
+
+ val virtualFile = myFixture.copyFileToProject(ktFile.absolutePath, "src/" + getTestName(true) + ".kt");
+ myFixture.configureFromExistingVirtualFile(virtualFile)
+
+ myFixture.doHighlighting()
+ myFixture.checkHighlighting(true, false, false)
+ }
+
+ override fun getTestDataPath() = KotlinTestUtils.getHomeDirectory() + "/plugins/uast-kotlin/testData/lint/"
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/test/org.jetbrains.kotlin.uast/AbstractKotlinUastStructureTest.kt b/plugins/uast-kotlin/test/org.jetbrains.kotlin.uast/AbstractKotlinUastStructureTest.kt
index 68523225870..6e64a9d3b35 100644
--- a/plugins/uast-kotlin/test/org.jetbrains.kotlin.uast/AbstractKotlinUastStructureTest.kt
+++ b/plugins/uast-kotlin/test/org.jetbrains.kotlin.uast/AbstractKotlinUastStructureTest.kt
@@ -30,7 +30,7 @@ abstract class AbstractKotlinUastStructureTest : KotlinLightCodeInsightFixtureTe
val renderFile = File(File(testDataPath, "render"), "$testName.txt")
val psiFile = myFixture.file
- val uElement = KotlinConverter.convertWithParent(psiFile) ?: error("UFile was not created")
+ val uElement = KotlinUastLanguagePlugin.converter.convertWithParent(psiFile) ?: error("UFile was not created")
val logActual = uElement.logString()
val renderActual = uElement.renderString()
diff --git a/plugins/uast-kotlin/test/org/jetbrains/kotlin/uast/KotlinLintTestGenerated.java b/plugins/uast-kotlin/test/org/jetbrains/kotlin/uast/KotlinLintTestGenerated.java
new file mode 100644
index 00000000000..b806b250fbc
--- /dev/null
+++ b/plugins/uast-kotlin/test/org/jetbrains/kotlin/uast/KotlinLintTestGenerated.java
@@ -0,0 +1,169 @@
+/*
+ * 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.uast;
+
+import com.intellij.testFramework.TestDataPath;
+import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
+import org.jetbrains.kotlin.test.KotlinTestUtils;
+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("plugins/uast-kotlin/testData/lint")
+@TestDataPath("$PROJECT_ROOT")
+@RunWith(JUnit3RunnerWithInners.class)
+public class KotlinLintTestGenerated extends AbstractKotlinLintTest {
+ @TestMetadata("alarm.kt")
+ public void testAlarm() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/alarm.kt");
+ doTest(fileName);
+ }
+
+ public void testAllFilesPresentInLint() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/uast-kotlin/testData/lint"), Pattern.compile("^(.+)\\.kt$"), true);
+ }
+
+ @TestMetadata("apiCheck.kt")
+ public void testApiCheck() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/apiCheck.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("callSuper.kt")
+ public void testCallSuper() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/callSuper.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("javaPerformance.kt")
+ public void testJavaPerformance() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/javaPerformance.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("javaScriptInterface.kt")
+ public void testJavaScriptInterface() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/javaScriptInterface.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("layoutInflation.kt")
+ public void testLayoutInflation() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/layoutInflation.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("log.kt")
+ public void testLog() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/log.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("noInternationalSms.kt")
+ public void testNoInternationalSms() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/noInternationalSms.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("overrideConcrete.kt")
+ public void testOverrideConcrete() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/overrideConcrete.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("parcel.kt")
+ public void testParcel() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/parcel.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("sdCardTest.kt")
+ public void testSdCardTest() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/sdCardTest.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("setJavaScriptEnabled.kt")
+ public void testSetJavaScriptEnabled() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/setJavaScriptEnabled.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("sharedPrefs.kt")
+ public void testSharedPrefs() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/sharedPrefs.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("sqlite.kt")
+ public void testSqlite() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/sqlite.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("systemServices.kt")
+ public void testSystemServices() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/systemServices.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("toast.kt")
+ public void testToast() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/toast.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("valueOf.kt")
+ public void testValueOf() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/valueOf.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("viewConstructor.kt")
+ public void testViewConstructor() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/viewConstructor.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("viewHolder.kt")
+ public void testViewHolder() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/viewHolder.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("wrongAnnotation.kt")
+ public void testWrongAnnotation() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/wrongAnnotation.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("wrongImport.kt")
+ public void testWrongImport() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/wrongImport.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("wrongViewCall.kt")
+ public void testWrongViewCall() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("plugins/uast-kotlin/testData/lint/wrongViewCall.kt");
+ doTest(fileName);
+ }
+}
diff --git a/plugins/uast-kotlin/testData/lint/alarm.kt b/plugins/uast-kotlin/testData/lint/alarm.kt
new file mode 100644
index 00000000000..fc067effaad
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/alarm.kt
@@ -0,0 +1,24 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintShortAlarmInspection
+
+import android.app.AlarmManager
+
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class TestAlarm {
+ fun test(alarmManager: AlarmManager) {
+ alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, 5000, 60000, null); // OK
+ alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, 6000, 70000, null); // OK
+ alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, 50, 10, null); // ERROR
+
+ alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, 5000, // ERROR
+ OtherClass.MY_INTERVAL, null); // ERROR
+
+ // Check value flow analysis, currently unsupported
+ val interval = 10;
+ val interval2 = 2L * interval;
+ alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, 5000, interval2, null); // ERROR
+ }
+
+ private object OtherClass {
+ val MY_INTERVAL = 1000L;
+ }
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/apiCheck.kt b/plugins/uast-kotlin/testData/lint/apiCheck.kt
new file mode 100644
index 00000000000..6fa830e19b9
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/apiCheck.kt
@@ -0,0 +1,270 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection
+// INSPECTION_CLASS2: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintInlinedApiInspection
+// INSPECTION_CLASS3: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintOverrideInspection
+
+import android.animation.RectEvaluator
+import android.annotation.TargetApi
+import org.w3c.dom.DOMError
+import org.w3c.dom.DOMErrorHandler
+import org.w3c.dom.DOMLocator
+
+import android.view.ViewGroup.LayoutParams
+import android.app.Activity
+import android.app.ApplicationErrorReport
+import android.graphics.PorterDuff
+import android.graphics.Rect
+import android.os.Build
+import android.widget.Chronometer
+import android.widget.GridLayout
+import dalvik.bytecode.OpcodeInfo
+
+import android.os.Build.VERSION
+import android.os.Build.VERSION.SDK_INT
+import android.os.Build.VERSION_CODES
+import android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH
+import android.os.Build.VERSION_CODES.JELLY_BEAN
+import android.widget.TextView
+
+@Suppress("SENSELESS_COMPARISON", "UNUSED_EXPRESSION", "UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class ApiCallTest: Activity() {
+
+ fun method(chronometer: Chronometer, locator: DOMLocator) {
+
+ // Virtual call
+ getActionBar() // API 11
+ actionBar // API 11
+
+ // Class references (no call or field access)
+ val error: DOMError? = null // API 8
+ val clz = DOMErrorHandler::class // API 8
+
+ // Method call
+ chronometer.onChronometerTickListener // API 3
+
+ // Inherited method call (from TextView
+ chronometer.setTextIsSelectable(true) // API 11
+
+ GridLayout::class
+
+ // Field access
+ val field = OpcodeInfo.MAXIMUM_VALUE // API 11
+
+
+ val fillParent = LayoutParams.FILL_PARENT // API 1
+ // This is a final int, which means it gets inlined
+ val matchParent = LayoutParams.MATCH_PARENT // API 8
+ // Field access: non final
+ val batteryInfo = report!!.batteryInfo
+
+ // Enum access
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
+ val mode = PorterDuff.Mode.OVERLAY // API 11
+ }
+ }
+
+ fun test(rect: Rect) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ RectEvaluator(rect); // OK
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ if (rect != null) {
+ RectEvaluator(rect); // OK
+ }
+ }
+ }
+
+ fun test2(rect: Rect) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ RectEvaluator(rect); // OK
+ }
+ }
+
+ fun test3(rect: Rect) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
+ RectEvaluator(); // ERROR
+ }
+ }
+
+ fun test4(rect: Rect) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ System.out.println("Something");
+ RectEvaluator(rect); // OK
+ } else {
+ RectEvaluator(rect); // ERROR
+ }
+ }
+
+ fun test5(rect: Rect) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
+ RectEvaluator(rect); // ERROR
+ } else {
+ RectEvaluator(rect); // ERROR
+ }
+ }
+
+ fun test(priority: Boolean) {
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null).getOrientation(); // Flagged
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null).getOrientation(); // Flagged
+ }
+
+ if (SDK_INT >= ICE_CREAM_SANDWICH) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null).getOrientation(); // Flagged
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null).getOrientation(); // Flagged
+ }
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ GridLayout(null).getOrientation(); // Flagged
+ } else {
+ GridLayout(null).getOrientation(); // Not flagged
+ }
+
+ if (Build.VERSION.SDK_INT >= 14) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null).getOrientation(); // Flagged
+ }
+
+ if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null).getOrientation(); // Flagged
+ }
+
+ // Nested conditionals
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ if (priority) {
+ GridLayout(null).getOrientation(); // Flagged
+ } else {
+ GridLayout(null).getOrientation(); // Flagged
+ }
+ } else {
+ GridLayout(null).getOrientation(); // Flagged
+ }
+
+ // Nested conditionals 2
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ if (priority) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null).getOrientation(); // Not flagged
+ }
+ } else {
+ GridLayout(null); // Flagged
+ }
+ }
+
+ fun test2(priority: Boolean) {
+ if (android.os.Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null); // Flagged
+ }
+
+ if (android.os.Build.VERSION.SDK_INT >= 16) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null); // Flagged
+ }
+
+ if (android.os.Build.VERSION.SDK_INT >= 13) {
+ GridLayout(null).getOrientation(); // Flagged
+ } else {
+ GridLayout(null); // Flagged
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null); // Flagged
+ }
+
+ if (SDK_INT >= JELLY_BEAN) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null); // Flagged
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null); // Flagged
+ }
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+ GridLayout(null); // Flagged
+ } else {
+ GridLayout(null).getOrientation(); // Not flagged
+ }
+
+ if (Build.VERSION.SDK_INT >= 16) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null); // Flagged
+ }
+
+ if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
+ GridLayout(null).getOrientation(); // Not flagged
+ } else {
+ GridLayout(null); // Flagged
+ }
+ }
+
+ fun test(textView: TextView) {
+ if (textView.isSuggestionsEnabled()) {
+ //ERROR
+ }
+ if (textView.isSuggestionsEnabled) {
+ //ERROR
+ }
+
+ if (SDK_INT >= JELLY_BEAN && textView.isSuggestionsEnabled()) {
+ //NO ERROR
+ }
+
+ if (SDK_INT >= JELLY_BEAN && textView.isSuggestionsEnabled) {
+ //NO ERROR
+ }
+
+ if (SDK_INT < JELLY_BEAN && textView.isSuggestionsEnabled()) {
+ //ERROR
+ }
+
+ if (SDK_INT < JELLY_BEAN && textView.isSuggestionsEnabled) {
+ //ERROR
+ }
+ }
+
+ @TargetApi(JELLY_BEAN)
+ fun testWithAnnotation(textView: TextView) {
+ if (textView.isSuggestionsEnabled()) {
+ //NO ERROR, annotation
+ }
+
+ if (textView.isSuggestionsEnabled) {
+ //NO ERROR, annotation
+ }
+ }
+
+ // Return type
+ internal // API 14
+ val gridLayout: GridLayout?
+ get() = null
+
+ private val report: ApplicationErrorReport?
+ get() = null
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/callSuper.kt b/plugins/uast-kotlin/testData/lint/callSuper.kt
new file mode 100644
index 00000000000..df30cfe7670
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/callSuper.kt
@@ -0,0 +1,97 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintMissingSuperCallInspection
+
+package android.support.annotation
+
+@Retention(AnnotationRetention.BINARY)
+@Target(AnnotationTarget.FUNCTION)
+annotation class CallSuper
+
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class CallSuperTest {
+ private class Child : Parent() {
+ override fun test1() {
+ // ERROR
+ }
+
+ override fun test2() {
+ // ERROR
+ }
+
+ override fun test3() {
+ // ERROR
+ }
+
+ override fun test4(arg: Int) {
+ // ERROR
+ }
+
+ override fun test4(arg: String) {
+ // OK
+ }
+
+
+ override fun test5(arg1: Int, arg2: Boolean, arg3: Map, *>, // ERROR
+ arg4: Array, vararg arg5: Int) {
+ }
+
+ override fun test5() {
+ // ERROR
+ super.test6() // (wrong super)
+ }
+
+ override fun test6() {
+ // OK
+ val x = 5
+ super.test6()
+ System.out.println(x)
+ }
+ }
+
+ private open class Parent : ParentParent() {
+ @CallSuper
+ protected open fun test1() {
+ }
+
+ override fun test3() {
+ super.test3()
+ }
+
+ @CallSuper
+ protected open fun test4(arg: Int) {
+ }
+
+ protected open fun test4(arg: String) {
+ }
+
+ @CallSuper
+ protected open fun test5() {
+ }
+
+ @CallSuper
+ protected open fun test5(arg1: Int, arg2: Boolean, arg3: Map, *>,
+ arg4: Array, vararg arg5: Int) {
+ }
+ }
+
+ private open class ParentParent : ParentParentParent() {
+ @CallSuper
+ protected open fun test2() {
+ }
+
+ @CallSuper
+ protected open fun test3() {
+ }
+
+ @CallSuper
+ protected open fun test6() {
+ }
+
+ @CallSuper
+ protected fun test7() {
+ }
+
+
+ }
+
+ private open class ParentParentParent
+}
diff --git a/plugins/uast-kotlin/testData/lint/javaPerformance.kt b/plugins/uast-kotlin/testData/lint/javaPerformance.kt
new file mode 100644
index 00000000000..2b7e32cc01c
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/javaPerformance.kt
@@ -0,0 +1,193 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintDrawAllocationInspection
+// INSPECTION_CLASS2: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUseSparseArraysInspection
+// INSPECTION_CLASS3: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUseValueOfInspection
+
+import java.util.HashMap
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.*
+import android.util.AttributeSet
+import android.util.SparseArray
+import android.widget.Button
+
+@SuppressWarnings("unused")
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class JavaPerformanceTest(context: Context, attrs: AttributeSet, defStyle: Int) : Button(context, attrs, defStyle) {
+
+ private var cachedRect: Rect? = null
+ private var shader: Any? = null
+ private var lastHeight: Int = 0
+ private var lastWidth: Int = 0
+
+ override fun onDraw(canvas: android.graphics.Canvas) {
+ super.onDraw(canvas)
+
+ // Various allocations:
+ java.lang.String("foo")
+ val s = java.lang.String("bar")
+
+ // This one should not be reported:
+ @SuppressLint("DrawAllocation")
+ val i = 5
+
+ // Cached object initialized lazily: should not complain about these
+ if (cachedRect == null) {
+ cachedRect = Rect(0, 0, 100, 100)
+ }
+ if (cachedRect == null || cachedRect!!.width() != 50) {
+ cachedRect = Rect(0, 0, 50, 100)
+ }
+
+ val b = java.lang.Boolean.valueOf(true)!! // auto-boxing
+ dummy(1, 2)
+
+ // Non-allocations
+ super.animate()
+ dummy2(1, 2)
+
+ // This will involve allocations, but we don't track
+ // inter-procedural stuff here
+ someOtherMethod()
+ }
+
+ internal fun dummy(foo: Int?, bar: Int) {
+ dummy2(foo!!, bar)
+ }
+
+ internal fun dummy2(foo: Int, bar: Int) {
+ }
+
+ internal fun someOtherMethod() {
+ // Allocations are okay here
+ java.lang.String("foo")
+ val s = java.lang.String("bar")
+ val b = java.lang.Boolean.valueOf(true)!! // auto-boxing
+
+
+ // Sparse array candidates
+ val myMap = HashMap()
+ // Should use SparseBooleanArray
+ val myBoolMap = HashMap()
+ // Should use SparseIntArray
+ val myIntMap = java.util.HashMap()
+
+ // This one should not be reported:
+ @SuppressLint("UseSparseArrays")
+ val myOtherMap = HashMap()
+ }
+
+ protected fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int,
+ x: Boolean) {
+ // wrong signature
+ java.lang.String("not an error")
+ }
+
+ protected fun onMeasure(widthMeasureSpec: Int) {
+ // wrong signature
+ java.lang.String("not an error")
+ }
+
+ protected fun onLayout(changed: Boolean, left: Int, top: Int, right: Int,
+ bottom: Int, wrong: Int) {
+ // wrong signature
+ java.lang.String("not an error")
+ }
+
+ protected fun onLayout(changed: Boolean, left: Int, top: Int, right: Int) {
+ // wrong signature
+ java.lang.String("not an error")
+ }
+
+ override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int,
+ bottom: Int) {
+ java.lang.String("flag me")
+ }
+
+ @SuppressWarnings("null") // not real code
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ java.lang.String("flag me")
+
+ // Forbidden factory methods:
+ Bitmap.createBitmap(100, 100, null)
+ android.graphics.Bitmap.createScaledBitmap(null, 100, 100, false)
+ BitmapFactory.decodeFile(null)
+ val canvas: Canvas? = null
+ canvas!!.getClipBounds() // allocates on your behalf
+ canvas.clipBounds // allocates on your behalf
+ canvas.getClipBounds(null) // NOT an error
+
+ val layoutWidth = width
+ val layoutHeight = height
+ if (mAllowCrop && (mOverlay == null || mOverlay!!.width != layoutWidth ||
+ mOverlay!!.height != layoutHeight)) {
+ mOverlay = Bitmap.createBitmap(layoutWidth, layoutHeight, Bitmap.Config.ARGB_8888)
+ mOverlayCanvas = Canvas(mOverlay!!)
+ }
+
+ if (widthMeasureSpec == 42) {
+ throw IllegalStateException("Test") // NOT an allocation
+ }
+
+ // More lazy init tests
+ var initialized = false
+ if (!initialized) {
+ java.lang.String("foo")
+ initialized = true
+ }
+
+ // NOT lazy initialization
+ if (!initialized || mOverlay == null) {
+ java.lang.String("foo")
+ }
+ }
+
+ internal fun factories() {
+ val i1 = 42
+ val l1 = 42L
+ val b1 = true
+ val c1 = 'c'
+ val f1 = 1.0f
+ val d1 = 1.0
+
+ // The following should not generate errors:
+ val i3 = Integer.valueOf(42)
+ }
+
+ private val mAllowCrop: Boolean = false
+ private var mOverlayCanvas: Canvas? = null
+ private var mOverlay: Bitmap? = null
+
+ override fun layout(l: Int, t: Int, r: Int, b: Int) {
+ // Using "this." to reference fields
+ if (this.shader == null)
+ this.shader = LinearGradient(0f, 0f, width.toFloat(), 0f, intArrayOf(0), null,
+ Shader.TileMode.REPEAT)
+
+ val width = width
+ val height = height
+
+ if (shader == null || lastWidth != width || lastHeight != height) {
+ lastWidth = width
+ lastHeight = height
+
+ shader = LinearGradient(0f, 0f, width.toFloat(), 0f, intArrayOf(0), null, Shader.TileMode.REPEAT)
+ }
+ }
+
+ fun inefficientSparseArray() {
+ SparseArray() // Use SparseIntArray instead
+ SparseArray() // Use SparseLongArray instead
+ SparseArray() // Use SparseBooleanArray instead
+ SparseArray() // OK
+ }
+
+ fun longSparseArray() {
+ // but only minSdkVersion >= 17 or if has v4 support lib
+ val myStringMap = HashMap()
+ }
+
+ fun byteSparseArray() {
+ // bytes easily apply to ints
+ val myByteMap = HashMap()
+ }
+}
diff --git a/plugins/uast-kotlin/testData/lint/javaScriptInterface.kt b/plugins/uast-kotlin/testData/lint/javaScriptInterface.kt
new file mode 100644
index 00000000000..3b4d09c7215
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/javaScriptInterface.kt
@@ -0,0 +1,58 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintJavascriptInterfaceInspection
+
+import android.annotation.SuppressLint
+import android.webkit.JavascriptInterface
+import android.webkit.WebView
+
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "UNUSED_VALUE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class JavaScriptTestK {
+ fun test(webview: WebView) {
+ webview.addJavascriptInterface(AnnotatedObject(), "myobj")
+
+ webview.addJavascriptInterface(InheritsFromAnnotated(), "myobj")
+ webview.addJavascriptInterface(NonAnnotatedObject(), "myobj")
+
+ var o: Any = NonAnnotatedObject()
+ webview.addJavascriptInterface(o, "myobj")
+ o = InheritsFromAnnotated()
+ webview.addJavascriptInterface(o, "myobj")
+ }
+
+ fun test(webview: WebView, object1: AnnotatedObject, object2: NonAnnotatedObject) {
+ webview.addJavascriptInterface(object1, "myobj")
+ webview.addJavascriptInterface(object2, "myobj")
+ }
+
+ @SuppressLint("JavascriptInterface")
+ fun testSuppressed(webview: WebView) {
+ webview.addJavascriptInterface(NonAnnotatedObject(), "myobj")
+ }
+
+ fun testLaterReassignment(webview: WebView) {
+ var o: Any = NonAnnotatedObject()
+ val t = o
+ webview.addJavascriptInterface(t, "myobj")
+ o = AnnotatedObject()
+ }
+
+ class NonAnnotatedObject() {
+ fun test1() {}
+ fun test2() {}
+ }
+
+ open class AnnotatedObject {
+ @JavascriptInterface
+ open fun test1() {}
+
+ open fun test2() {}
+
+ @JavascriptInterface
+ fun test3() {}
+ }
+
+ class InheritsFromAnnotated : AnnotatedObject() {
+ override fun test1() {}
+ override fun test2() {}
+ }
+
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/layoutInflation.kt b/plugins/uast-kotlin/testData/lint/layoutInflation.kt
new file mode 100644
index 00000000000..65bd1e77cf5
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/layoutInflation.kt
@@ -0,0 +1,50 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintInflateParamsInspection
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.BaseAdapter
+
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+abstract class LayoutInflationTest : BaseAdapter() {
+ lateinit var mInflater: LayoutInflater
+
+ override fun getView(position: Int, convertView: View, parent: ViewGroup): View {
+ var view = convertView
+ view = mInflater.inflate(R.layout.your_layout, null)
+ view = mInflater.inflate(R.layout.your_layout, null, true)
+ view = mInflater.inflate(R.layout.your_layout, parent)
+ view = WeirdInflater.inflate(view, null)
+
+ return view
+ }
+
+ object WeirdInflater {
+ fun inflate(view: View, parent: View?) = view
+ }
+
+ object R {
+ object layout {
+ val your_layout = 1
+ }
+ }
+}
+
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+abstract class LayoutInflationTest2 : BaseAdapter() {
+ lateinit var mInflater: LayoutInflater
+
+ override fun getView(position: Int, convertView: View, parent: ViewGroup): View? {
+ return if (true) {
+ mInflater.inflate(R.layout.your_layout, parent)
+ } else {
+ null
+ }
+ }
+
+ object R {
+ object layout {
+ val your_layout = 1
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/log.kt b/plugins/uast-kotlin/testData/lint/log.kt
new file mode 100644
index 00000000000..7ce3a11e3c9
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/log.kt
@@ -0,0 +1,111 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintLogConditionalInspection
+// INSPECTION_CLASS2: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintLogTagMismatchInspection
+// INSPECTION_CLASS3: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintLongLogTagInspection
+
+import android.annotation.SuppressLint
+import android.util.Log
+import android.util.Log.DEBUG
+
+@SuppressWarnings("UnusedDeclaration")
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class LogTest {
+
+ fun checkConditional(m: String) {
+ Log.d(TAG1, "message") // ok: unconditional, but not performing computation
+ Log.d(TAG1, m) // ok: unconditional, but not performing computation
+ Log.d(TAG1, "a" + "b") // ok: unconditional, but not performing non-constant computation
+ Log.d(TAG1, Constants.MY_MESSAGE) // ok: unconditional, but constant string
+ Log.i(TAG1, "message" + m) // error: unconditional w/ computation
+ Log.i(TAG1, toString()) // error: unconditional w/ computation
+ Log.e(TAG1, toString()) // ok: only flagging debug/info messages
+ Log.w(TAG1, toString()) // ok: only flagging debug/info messages
+ Log.wtf(TAG1, toString()) // ok: only flagging debug/info messages
+ if (Log.isLoggable(TAG1, 0)) {
+ Log.d(TAG1, toString()) // ok: conditional
+ }
+ }
+
+ fun checkWrongTag(tag: String) {
+ if (Log.isLoggable(TAG1, Log.DEBUG)) {
+ Log.d(TAG2, "message") // warn: mismatched tags!
+ }
+ if (Log.isLoggable("my_tag", Log.DEBUG)) {
+ Log.d("other_tag", "message") // warn: mismatched tags!
+ }
+ if (Log.isLoggable("my_tag", Log.DEBUG)) {
+ Log.d("my_tag", "message") // ok: strings equal
+ }
+ if (Log.isLoggable(tag, Log.DEBUG)) {
+ Log.d(tag, "message") // ok: same variable
+ }
+ }
+
+ fun checkLongTag(shouldLog: Boolean) {
+ if (shouldLog) {
+ // String literal tags
+ Log.d("short_tag", "message") // ok: short
+ Log.d("really_really_really_really_really_long_tag", "message") // error: too long
+
+ // Resolved field tags
+ Log.d(TAG1, "message") // ok: short
+ Log.d(TAG22, "message") // ok: short
+ Log.d(TAG23, "message") // ok: threshold
+ Log.d(TAG24, "message") // error: too long
+ Log.d(LONG_TAG, "message") // error: way too long
+
+ // Locally defined variable tags
+ val LOCAL_TAG = "MyReallyReallyReallyReallyReallyLongTag"
+ Log.d(LOCAL_TAG, "message") // error: too long
+
+ // Concatenated tags
+ Log.d(TAG22 + TAG1, "message") // error: too long
+ Log.d(TAG22 + "MyTag", "message") // error: too long
+ }
+ }
+
+ fun checkWrongLevel(tag: String) {
+ if (Log.isLoggable(TAG1, Log.DEBUG)) {
+ Log.d(TAG1, "message") // ok: right level
+ }
+ if (Log.isLoggable(TAG1, Log.INFO)) {
+ Log.i(TAG1, "message") // ok: right level
+ }
+ if (Log.isLoggable(TAG1, Log.DEBUG)) {
+ Log.v(TAG1, "message") // warn: wrong level
+ }
+ if (Log.isLoggable(TAG1, DEBUG)) {
+ // static import of level
+ Log.v(TAG1, "message") // warn: wrong level
+ }
+ if (Log.isLoggable(TAG1, Log.VERBOSE)) {
+ Log.d(TAG1, "message") // warn? verbose is a lower logging level, which includes debug
+ }
+ if (Log.isLoggable(TAG1, Constants.MY_LEVEL)) {
+ Log.d(TAG1, "message") // ok: unknown level alias
+ }
+ }
+
+ @SuppressLint("all")
+ fun suppressed1() {
+ Log.d(TAG1, "message") // ok: suppressed
+ }
+
+ @SuppressLint("LogConditional")
+ fun suppressed2() {
+ Log.d(TAG1, "message") // ok: suppressed
+ }
+
+ private object Constants {
+ val MY_MESSAGE = "My Message"
+ val MY_LEVEL = 5
+ }
+
+ companion object {
+ private val TAG1 = "MyTag1"
+ private val TAG2 = "MyTag2"
+ private val TAG22 = "1234567890123456789012"
+ private val TAG23 = "12345678901234567890123"
+ private val TAG24 = "123456789012345678901234"
+ private val LONG_TAG = "MyReallyReallyReallyReallyReallyLongTag"
+ }
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/noInternationalSms.kt b/plugins/uast-kotlin/testData/lint/noInternationalSms.kt
new file mode 100644
index 00000000000..31fecc25918
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/noInternationalSms.kt
@@ -0,0 +1,19 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUnlocalizedSmsInspection
+
+import android.content.Context
+import android.telephony.SmsManager
+
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class NonInternationalizedSmsDetectorTest {
+ private fun sendLocalizedMessage(context: Context) {
+ // Don't warn here
+ val sms = SmsManager.getDefault()
+ sms.sendTextMessage("+1234567890", null, null, null, null)
+ }
+
+ private fun sendAlternativeCountryPrefix(context: Context) {
+ // Do warn here
+ val sms = SmsManager.getDefault()
+ sms.sendMultipartTextMessage("001234567890", null, null, null, null)
+ }
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/overrideConcrete.kt b/plugins/uast-kotlin/testData/lint/overrideConcrete.kt
new file mode 100644
index 00000000000..55a5bb3c228
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/overrideConcrete.kt
@@ -0,0 +1,61 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintOverrideAbstractInspection
+
+import android.annotation.SuppressLint
+import android.annotation.TargetApi
+import android.os.Build
+import android.service.notification.NotificationListenerService
+import android.service.notification.StatusBarNotification
+
+@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class OverrideConcreteTest2 {
+ // OK: This one specifies both methods
+ private open class MyNotificationListenerService1 : NotificationListenerService() {
+ override fun onNotificationPosted(statusBarNotification: StatusBarNotification) {
+ }
+
+ override fun onNotificationRemoved(statusBarNotification: StatusBarNotification) {
+ }
+ }
+
+ // Error: Misses onNotificationPosted
+ private class MyNotificationListenerService2 : NotificationListenerService() {
+ override fun onNotificationRemoved(statusBarNotification: StatusBarNotification) {
+ }
+ }
+
+ // Error: Misses onNotificationRemoved
+ private open class MyNotificationListenerService3 : NotificationListenerService() {
+ override fun onNotificationPosted(statusBarNotification: StatusBarNotification) {
+ }
+ }
+
+ // Error: Missing both; wrong signatures (first has wrong arg count, second has wrong type)
+ private class MyNotificationListenerService4 : NotificationListenerService() {
+ fun onNotificationPosted(statusBarNotification: StatusBarNotification, flags: Int) {
+ }
+
+ fun onNotificationRemoved(statusBarNotification: Int) {
+ }
+ }
+
+ // OK: Inherits from a class which define both
+ private class MyNotificationListenerService5 : MyNotificationListenerService1()
+
+ // OK: Inherits from a class which defines only one, but the other one is defined here
+ private class MyNotificationListenerService6 : MyNotificationListenerService3() {
+ override fun onNotificationRemoved(statusBarNotification: StatusBarNotification) {
+ }
+ }
+
+ // Error: Inheriting from a class which only defines one
+ private class MyNotificationListenerService7 : MyNotificationListenerService3()
+
+ // OK: Has target api setting a local version that is high enough
+ @TargetApi(21)
+ private class MyNotificationListenerService8 : NotificationListenerService()
+
+ // OK: Suppressed
+ @SuppressLint("OverrideAbstract")
+ private class MyNotificationListenerService9 : MyNotificationListenerService1()
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/parcel.kt b/plugins/uast-kotlin/testData/lint/parcel.kt
new file mode 100644
index 00000000000..4434a6bf8a0
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/parcel.kt
@@ -0,0 +1,37 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintParcelCreatorInspection
+
+@file:Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+import android.os.Parcel
+import android.os.Parcelable
+
+class MyParcelable1 : Parcelable {
+ override fun describeContents() = 0
+ override fun writeToParcel(arg0: Parcel, arg1: Int) {}
+}
+
+internal class MyParcelable2 : Parcelable {
+ override fun describeContents() = 0
+
+ override fun writeToParcel(arg0: Parcel, arg1: Int) {}
+
+ companion object {
+ val CREATOR: Parcelable.Creator = object : Parcelable.Creator {
+ override fun newArray(size: Int) = null!!
+ override fun createFromParcel(source: Parcel?) = null!!
+ }
+ }
+}
+
+internal class MyParcelable3 : Parcelable {
+ override fun describeContents() = 0
+ override fun writeToParcel(arg0: Parcel, arg1: Int) {}
+
+ companion object {
+ val CREATOR = 0 // Wrong type
+ }
+}
+
+internal abstract class MyParcelable4 : Parcelable {
+ override fun describeContents() = 0
+ override fun writeToParcel(arg0: Parcel, arg1: Int) {}
+}
diff --git a/plugins/uast-kotlin/testData/lint/sdCardTest.kt b/plugins/uast-kotlin/testData/lint/sdCardTest.kt
new file mode 100644
index 00000000000..41c48d48afb
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/sdCardTest.kt
@@ -0,0 +1,40 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSdCardPathInspection
+
+import java.io.File
+import android.content.Intent
+import android.net.Uri
+
+/**
+ * Ignore comments - create("/sdcard/foo")
+ */
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class SdCardTest {
+ internal var deviceDir = File("/sdcard/vr")
+
+ init {
+ if (PROFILE_STARTUP) {
+ android.os.Debug.startMethodTracing("/sdcard/launcher")
+ }
+
+ if (File("/sdcard").exists()) {
+ }
+ val FilePath = "/sdcard/" + File("test")
+ System.setProperty("foo.bar", "file://sdcard")
+
+
+ val intent = Intent(Intent.ACTION_PICK)
+ intent.setDataAndType(Uri.parse("file://sdcard/foo.json"), "application/bar-json")
+ intent.putExtra("path-filter", "/sdcard(/.+)*")
+ intent.putExtra("start-dir", "/sdcard")
+ val mypath = "/data/data/foo"
+ val base = "/data/data/foo.bar/test-profiling"
+ val s = "file://sdcard/foo"
+}
+
+companion object {
+ private val PROFILE_STARTUP = true
+ private val SDCARD_TEST_HTML = "/sdcard/test.html"
+ val SDCARD_ROOT = "/sdcard"
+ val PACKAGES_PATH = "/sdcard/o/packages/"
+}
+}
diff --git a/plugins/uast-kotlin/testData/lint/setJavaScriptEnabled.kt b/plugins/uast-kotlin/testData/lint/setJavaScriptEnabled.kt
new file mode 100644
index 00000000000..2c115572e2a
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/setJavaScriptEnabled.kt
@@ -0,0 +1,24 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSetJavaScriptEnabledInspection
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.webkit.WebView
+
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+public class HelloWebApp : Activity() {
+
+ fun test(webView: WebView) {
+ webView.settings.javaScriptEnabled = true // bad
+ webView.getSettings().setJavaScriptEnabled(true) // bad
+ webView.getSettings().setJavaScriptEnabled(false) // good
+ webView.loadUrl("file:///android_asset/www/index.html")
+ }
+
+ @SuppressLint("SetJavaScriptEnabled")
+ fun suppressed(webView: WebView) {
+ webView.getSettings().javaScriptEnabled = true; // bad
+ webView.getSettings().setJavaScriptEnabled(true) // bad
+ webView.getSettings().setJavaScriptEnabled(false); // good
+ webView.loadUrl("file:///android_asset/www/index.html");
+ }
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/sharedPrefs.kt b/plugins/uast-kotlin/testData/lint/sharedPrefs.kt
new file mode 100644
index 00000000000..cfb18d9afe3
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/sharedPrefs.kt
@@ -0,0 +1,69 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintCommitPrefEditsInspection
+
+import android.app.Activity
+import android.content.Context
+import android.os.Bundle
+import android.preference.PreferenceManager
+
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class SharedPrefsText(context: Context) : Activity() {
+ // OK 1
+ fun onCreate1(savedInstanceState: Bundle) {
+ super.onCreate(savedInstanceState)
+ val preferences = PreferenceManager.getDefaultSharedPreferences(this)
+ val editor = preferences.edit()
+ editor.putString("foo", "bar")
+ editor.putInt("bar", 42)
+ editor.commit()
+ }
+
+ // OK 2
+ fun onCreate2(savedInstanceState: Bundle, apply: Boolean) {
+ super.onCreate(savedInstanceState)
+ val preferences = PreferenceManager.getDefaultSharedPreferences(this)
+ val editor = preferences.edit()
+ editor.putString("foo", "bar")
+ editor.putInt("bar", 42)
+ if (apply) {
+ editor.apply()
+ }
+ }
+
+ // Not a bug
+ fun test(foo: Foo) {
+ val bar1 = foo.edit()
+ val bar3 = edit()
+ apply()
+ }
+
+ internal fun apply() {
+
+ }
+
+ fun edit(): Bar {
+ return Bar()
+ }
+
+ class Foo {
+ internal fun edit(): Bar {
+ return Bar()
+ }
+ }
+
+ class Bar
+
+ // Bug
+ fun bug1(savedInstanceState: Bundle) {
+ super.onCreate(savedInstanceState)
+ val preferences = PreferenceManager.getDefaultSharedPreferences(this)
+ val editor = preferences.edit()
+ editor.putString("foo", "bar")
+ editor.putInt("bar", 42)
+ }
+
+ init {
+ val preferences = PreferenceManager.getDefaultSharedPreferences(context)
+ val editor = preferences.edit()
+ editor.putString("foo", "bar")
+ }
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/sqlite.kt b/plugins/uast-kotlin/testData/lint/sqlite.kt
new file mode 100644
index 00000000000..95da6d3f5f4
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/sqlite.kt
@@ -0,0 +1,7 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSQLiteStringInspection
+
+import android.database.sqlite.SQLiteDatabase
+
+fun test(db: SQLiteDatabase) {
+ db.execSQL("CREATE TABLE COMPANY(NAME STRING)")
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/systemServices.kt b/plugins/uast-kotlin/testData/lint/systemServices.kt
new file mode 100644
index 00000000000..2e6860502b0
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/systemServices.kt
@@ -0,0 +1,29 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintServiceCastInspection
+
+import android.content.ClipboardManager
+import android.app.Activity
+import android.app.WallpaperManager
+import android.content.Context
+import android.hardware.display.DisplayManager
+import android.service.wallpaper.WallpaperService
+
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class SystemServiceTest : Activity() {
+
+ fun test1() {
+ val displayServiceOk = getSystemService(DISPLAY_SERVICE) as DisplayManager
+ val displayServiceWrong = getSystemService(DEVICE_POLICY_SERVICE) as DisplayManager
+ val wallPaperOk = getSystemService(WALLPAPER_SERVICE) as WallpaperService
+ val wallPaperWrong = getSystemService(WALLPAPER_SERVICE) as WallpaperManager
+ }
+
+ fun test2(context: Context) {
+ val displayServiceOk = context.getSystemService(DISPLAY_SERVICE) as DisplayManager
+ val displayServiceWrong = context.getSystemService(DEVICE_POLICY_SERVICE) as DisplayManager
+ }
+
+ fun clipboard(context: Context) {
+ val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+ val clipboard2 = context.getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
+ }
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/toast.kt b/plugins/uast-kotlin/testData/lint/toast.kt
new file mode 100644
index 00000000000..a84df0e6b32
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/toast.kt
@@ -0,0 +1,55 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintShowToastInspection
+
+import android.app.Activity
+import android.content.Context
+import android.widget.Toast
+
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class ToastTest(context: Context) : Activity() {
+ private fun createToast(context: Context): Toast {
+ // Don't warn here
+ return Toast.makeText(context, "foo", Toast.LENGTH_LONG)
+ }
+
+ private fun showToast(context: Context) {
+ // Don't warn here
+ val toast = Toast.makeText(context, "foo", Toast.LENGTH_LONG)
+ System.out.println("Other intermediate code here")
+ val temp = 5 + 2
+ toast.show()
+ }
+
+ private fun showToast2(context: Context) {
+ // Don't warn here
+ val duration = Toast.LENGTH_LONG
+ Toast.makeText(context, "foo", Toast.LENGTH_LONG).show()
+ Toast.makeText(context, R.string.app_name, duration).show()
+ }
+
+ private fun broken(context: Context) {
+ // Errors
+ Toast.makeText(context, "foo", Toast.LENGTH_LONG)
+ val toast = Toast.makeText(context, R.string.app_name, 5000)
+ toast.duration
+ }
+
+ init {
+ Toast.makeText(context, "foo", Toast.LENGTH_LONG)
+ }
+
+ @android.annotation.SuppressLint("ShowToast")
+ private fun checkSuppress1(context: Context) {
+ val toast = Toast.makeText(this, "MyToast", Toast.LENGTH_LONG)
+ }
+
+ private fun checkSuppress2(context: Context) {
+ @android.annotation.SuppressLint("ShowToast")
+ val toast = Toast.makeText(this, "MyToast", Toast.LENGTH_LONG)
+ }
+
+ class R {
+ object string {
+ val app_name = 1
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/valueOf.kt b/plugins/uast-kotlin/testData/lint/valueOf.kt
new file mode 100644
index 00000000000..1702302715f
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/valueOf.kt
@@ -0,0 +1,8 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintUseValueOfInspection
+
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class Simple {
+ fun test() {
+ Integer(5)
+ }
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/viewConstructor.kt b/plugins/uast-kotlin/testData/lint/viewConstructor.kt
new file mode 100644
index 00000000000..2087cee75c4
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/viewConstructor.kt
@@ -0,0 +1,32 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintViewConstructorInspection
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import android.widget.TextView
+
+class View1(context: Context?) : View(context)
+class View2(context: Context?, attrs: AttributeSet?) : View(context, attrs)
+class View3(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : TextView(context, attrs, defStyleAttr)
+
+// Error
+class View4(int: Int, context: Context?) : View(context)
+
+// Error
+class View5(context: Context?, attrs: AttributeSet?, val name: String) : View(context, attrs)
+
+class View6 : View {
+ constructor(context: Context) : super(context) {
+
+ }
+}
+
+class View7 : View {
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+}
+
+// Error
+class View8 : View {
+ constructor(context: Context, a: Int) : super(context)
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/viewHolder.kt b/plugins/uast-kotlin/testData/lint/viewHolder.kt
new file mode 100644
index 00000000000..ad2f7fc07e9
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/viewHolder.kt
@@ -0,0 +1,154 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintViewHolderInspection
+
+@file:Suppress("NAME_SHADOWING", "unused", "UNUSED_VALUE", "VARIABLE_WITH_REDUNDANT_INITIALIZER", "UNUSED_VARIABLE")
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.BaseAdapter
+import android.widget.LinearLayout
+import android.widget.TextView
+import java.util.ArrayList
+
+@SuppressWarnings("ConstantConditions", "UnusedDeclaration")
+abstract class ViewHolderTest : BaseAdapter() {
+ override fun getCount() = 0
+ override fun getItem(position: Int) = null
+ override fun getItemId(position: Int) = 0L
+
+ class Adapter1 : ViewHolderTest() {
+ override fun getView(position: Int, convertView: View, parent: ViewGroup) = null
+ }
+
+ class Adapter2 : ViewHolderTest() {
+ lateinit var mInflater: LayoutInflater
+
+ override fun getView(position: Int, convertView: View, parent: ViewGroup): View {
+ var convertView = convertView
+ // Should use View Holder pattern here
+ convertView = mInflater.inflate(R.layout.your_layout, null)
+
+ val text = convertView.findViewById(R.id.text) as TextView
+ text.text = "Position " + position
+
+ return convertView
+ }
+ }
+
+ class Adapter3 : ViewHolderTest() {
+ lateinit var mInflater: LayoutInflater
+
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+ var convertView = convertView
+ // Already using View Holder pattern
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.your_layout, null)
+ }
+
+ val text = convertView!!.findViewById(R.id.text) as TextView
+ text.text = "Position " + position
+
+ return convertView
+ }
+ }
+
+ class Adapter4 : ViewHolderTest() {
+ lateinit var mInflater: LayoutInflater
+
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+ var convertView = convertView
+ // Already using View Holder pattern
+ //noinspection StatementWithEmptyBody
+ if (convertView != null) {
+ } else {
+ convertView = mInflater.inflate(R.layout.your_layout, null)
+ }
+
+ val text = convertView!!.findViewById(R.id.text) as TextView
+ text.text = "Position " + position
+
+ return convertView
+ }
+ }
+
+ class Adapter5 : ViewHolderTest() {
+ lateinit var mInflater: LayoutInflater
+
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+ var convertView = convertView
+ // Already using View Holder pattern
+ convertView = if (convertView == null) mInflater.inflate(R.layout.your_layout, null) else convertView
+
+ val text = convertView!!.findViewById(R.id.text) as TextView
+ text.text = "Position " + position
+
+ return convertView
+ }
+ }
+
+ class Adapter6 : ViewHolderTest() {
+ private val mContext: Context? = null
+ private var mLayoutInflator: LayoutInflater? = null
+ private lateinit var mLapTimes: ArrayList
+
+ override fun getView(position: Int, convertView: View, parent: ViewGroup): View {
+ if (mLayoutInflator == null)
+ mLayoutInflator = mContext!!.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
+
+ var v: View? = convertView
+ if (v == null) v = mLayoutInflator!!.inflate(R.layout.your_layout, null)
+
+ val listItemHolder = v!!.findViewById(R.id.laptimes_list_item_holder) as LinearLayout
+ listItemHolder.removeAllViews()
+
+ for (i in 1..5) {
+ val lapItemView = mLayoutInflator!!.inflate(R.layout.laptime_item, null)
+ if (i == 0) {
+ val t = lapItemView.findViewById(R.id.laptime_text) as TextView
+ }
+
+ val t2 = lapItemView.findViewById(R.id.laptime_text2) as TextView
+ if (i < mLapTimes.size - 1 && mLapTimes.size > 1) {
+ var laptime = mLapTimes[i] - mLapTimes[i + 1]
+ if (laptime < 0) laptime = mLapTimes[i]
+ }
+
+ listItemHolder.addView(lapItemView)
+
+ }
+ return v
+ }
+ }
+
+ class Adapter7 : ViewHolderTest() {
+ lateinit var inflater: LayoutInflater
+
+ override fun getView(position: Int, convertView: View, parent: ViewGroup): View {
+ var rootView: View? = convertView
+ val itemViewType = getItemViewType(position)
+ when (itemViewType) {
+ 0 -> {
+ if (rootView != null)
+ return rootView
+ rootView = inflater.inflate(android.R.layout.simple_list_item_1, parent, false)
+ }
+ }
+ return rootView!!
+ }
+ }
+
+ class R {
+ object layout {
+ val your_layout = 1
+ val laptime_item = 2
+ }
+
+ object id {
+ val laptime_text = 1
+ val laptime_text2 = 2
+ val laptimes_list_item_holder = 3
+ val text = 4
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/wrongAnnotation.kt b/plugins/uast-kotlin/testData/lint/wrongAnnotation.kt
new file mode 100644
index 00000000000..327362eeff4
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/wrongAnnotation.kt
@@ -0,0 +1,39 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintLocalSuppressInspection
+
+import android.annotation.SuppressLint
+import android.view.View
+
+@Suppress("UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
+class WrongAnnotation2 {
+ @SuppressLint("NewApi")
+ private val field1: Int = 0
+
+ @SuppressLint("NewApi")
+ private val field2 = 5
+
+ companion object {
+ @SuppressLint("NewApi") // Valid: class-file check on method
+ fun foobar(view: View, @SuppressLint("NewApi") foo: Int) {
+ // Invalid: class-file check
+ @SuppressLint("NewApi") // Invalid
+ val a: Boolean
+ @SuppressLint("SdCardPath", "NewApi") // Invalid: class-file based check on local variable
+ val b: Boolean
+ @android.annotation.SuppressLint("SdCardPath", "NewApi") // Invalid (FQN)
+ val c: Boolean
+ @SuppressLint("SdCardPath") // Valid: AST-based check
+ val d: Boolean
+ }
+
+ init {
+ // Local variable outside method: invalid
+ @SuppressLint("NewApi")
+ val localvar = 5
+ }
+
+ private fun test() {
+ @SuppressLint("NewApi") // Invalid
+ val a = View.MEASURED_STATE_MASK
+ }
+ }
+}
diff --git a/plugins/uast-kotlin/testData/lint/wrongImport.kt b/plugins/uast-kotlin/testData/lint/wrongImport.kt
new file mode 100644
index 00000000000..b688362b490
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/wrongImport.kt
@@ -0,0 +1,8 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintSuspiciousImportInspection
+
+//Warning
+import android.R
+
+fun a() {
+ R.id.button1
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/testData/lint/wrongViewCall.kt b/plugins/uast-kotlin/testData/lint/wrongViewCall.kt
new file mode 100644
index 00000000000..0ee6e922d91
--- /dev/null
+++ b/plugins/uast-kotlin/testData/lint/wrongViewCall.kt
@@ -0,0 +1,23 @@
+// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintWrongCallInspection
+
+import android.content.Context
+import android.graphics.Canvas
+import android.util.AttributeSet
+import android.widget.FrameLayout
+import android.widget.LinearLayout
+
+abstract class WrongViewCall(context: Context, attrs: AttributeSet, defStyle: Int) : LinearLayout(context, attrs, defStyle) {
+ private val child: MyChild? = null
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ child?.onDraw(canvas)
+ }
+
+ private inner class MyChild(context: Context, attrs: AttributeSet, defStyle: Int) : FrameLayout(context, attrs, defStyle) {
+
+ public override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ }
+ }
+}
diff --git a/plugins/uast-kotlin/uast-kotlin.iml b/plugins/uast-kotlin/uast-kotlin.iml
index 486fbdd1427..e86f5912532 100644
--- a/plugins/uast-kotlin/uast-kotlin.iml
+++ b/plugins/uast-kotlin/uast-kotlin.iml
@@ -20,5 +20,9 @@
+
+
+
+
\ No newline at end of file