diff --git a/plugins/kotlin/idea/resources/inspectionDescriptions/TypeParameterFindViewById.html b/plugins/kotlin/idea/resources/inspectionDescriptions/TypeParameterFindViewById.html new file mode 100644 index 000000000000..13c3dc2c2ed1 --- /dev/null +++ b/plugins/kotlin/idea/resources/inspectionDescriptions/TypeParameterFindViewById.html @@ -0,0 +1,5 @@ + + +Reports findViewById calls with type cast which can be converted to findViewById with type parameter from Android 8.0 (API level 26) + + \ No newline at end of file diff --git a/plugins/kotlin/idea/src/META-INF/android.xml b/plugins/kotlin/idea/src/META-INF/android.xml index 3e04ed2fa491..b6a5e9931eeb 100644 --- a/plugins/kotlin/idea/src/META-INF/android.xml +++ b/plugins/kotlin/idea/src/META-INF/android.xml @@ -12,10 +12,18 @@ + + diff --git a/plugins/kotlin/idea/tests/testData/android/lint/findViewById.kt b/plugins/kotlin/idea/tests/testData/android/lint/findViewById.kt new file mode 100644 index 000000000000..974ee5afd5a7 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/android/lint/findViewById.kt @@ -0,0 +1,49 @@ +// INSPECTION_CLASS: org.jetbrains.kotlin.android.inspection.TypeParameterFindViewByIdInspection + +import android.app.Activity +import android.os.Bundle +import android.widget.Button +import android.widget.TextView + +@Suppress( + "TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER", + "UNUSED_VARIABLE" +) +class OtherActivity : Activity() { + + override fun onCreate(savedInstanceState: Bundle) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_other) + + findViewById(R.id.tvHello) as TextView + val tvHello = findViewById(R.id.tvHello) as TextView + val btnGo = findViewById(R.id.btnGo) as Button? + + // should be ok, already has type parameter + val tvHello2 = findViewById(R.id.tvHello) as TextView + + // ok, we can't convert safe cast because semantic will be changed + val tvHello3 = findViewById(R.id.tvHello) as? TextView + + // ok, no cast + foo(findViewById(R.id.tvHello)) + + // ok, no cast + findViewById(R.id.tvHello) is TextView + } + + fun foo(view: TextView) { + view.text = "foo" + } +} + +class R { + object layout { + val activity_other = 100500 + } + + object id { + val tvHello = 0 + val btnGo = 1 + } +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/android/lint/viewHolder.kt b/plugins/kotlin/idea/tests/testData/android/lint/viewHolder.kt index ad2f7fc07e90..057b2d07aa85 100644 --- a/plugins/kotlin/idea/tests/testData/android/lint/viewHolder.kt +++ b/plugins/kotlin/idea/tests/testData/android/lint/viewHolder.kt @@ -29,7 +29,7 @@ abstract class ViewHolderTest : BaseAdapter() { // Should use View Holder pattern here convertView = mInflater.inflate(R.layout.your_layout, null) - val text = convertView.findViewById(R.id.text) as TextView + val text: TextView = convertView.findViewById(R.id.text) text.text = "Position " + position return convertView @@ -46,7 +46,7 @@ abstract class ViewHolderTest : BaseAdapter() { convertView = mInflater.inflate(R.layout.your_layout, null) } - val text = convertView!!.findViewById(R.id.text) as TextView + val text: TextView = convertView!!.findViewById(R.id.text) text.text = "Position " + position return convertView @@ -65,7 +65,7 @@ abstract class ViewHolderTest : BaseAdapter() { convertView = mInflater.inflate(R.layout.your_layout, null) } - val text = convertView!!.findViewById(R.id.text) as TextView + val text: TextView = convertView!!.findViewById(R.id.text) text.text = "Position " + position return convertView @@ -80,7 +80,7 @@ abstract class ViewHolderTest : BaseAdapter() { // 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 + val text: TextView = convertView!!.findViewById(R.id.text) text.text = "Position " + position return convertView @@ -99,16 +99,16 @@ abstract class ViewHolderTest : BaseAdapter() { 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 + val listItemHolder: LinearLayout = v!!.findViewById(R.id.laptimes_list_item_holder) listItemHolder.removeAllViews() for (i in 1..5) { - val lapItemView = mLayoutInflator!!.inflate(R.layout.laptime_item, null) + val lapItemView: View = mLayoutInflator!!.inflate(R.layout.laptime_item, null) if (i == 0) { - val t = lapItemView.findViewById(R.id.laptime_text) as TextView + val t: TextView = lapItemView.findViewById(R.id.laptime_text) } - val t2 = lapItemView.findViewById(R.id.laptime_text2) as TextView + val t2: TextView = lapItemView.findViewById(R.id.laptime_text2) if (i < mLapTimes.size - 1 && mLapTimes.size > 1) { var laptime = mLapTimes[i] - mLapTimes[i + 1] if (laptime < 0) laptime = mLapTimes[i] diff --git a/plugins/kotlin/idea/tests/testData/android/lintQuickfix/findViewById/nullableType.kt b/plugins/kotlin/idea/tests/testData/android/lintQuickfix/findViewById/nullableType.kt new file mode 100644 index 000000000000..b0ae9f7508bc --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/android/lintQuickfix/findViewById/nullableType.kt @@ -0,0 +1,28 @@ +// INTENTION_TEXT: Convert cast to findViewById with type parameter +// INSPECTION_CLASS: org.jetbrains.kotlin.android.inspection.TypeParameterFindViewByIdInspection + +import android.app.Activity +import android.os.Bundle +import android.widget.Button +import android.widget.TextView + + +class OtherActivity : Activity() { + + override fun onCreate(savedInstanceState: Bundle) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_other) + + val tvHello = findViewById(R.id.tvHello) as TextView? + } +} + +class R { + object layout { + val activity_other = 100500 + } + + object id { + val tvHello = 0 + } +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/android/lintQuickfix/findViewById/nullableType.kt.expected b/plugins/kotlin/idea/tests/testData/android/lintQuickfix/findViewById/nullableType.kt.expected new file mode 100644 index 000000000000..fbf229a7ee80 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/android/lintQuickfix/findViewById/nullableType.kt.expected @@ -0,0 +1,28 @@ +// INTENTION_TEXT: Convert cast to findViewById with type parameter +// INSPECTION_CLASS: org.jetbrains.kotlin.android.inspection.TypeParameterFindViewByIdInspection + +import android.app.Activity +import android.os.Bundle +import android.widget.Button +import android.widget.TextView + + +class OtherActivity : Activity() { + + override fun onCreate(savedInstanceState: Bundle) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_other) + + val tvHello = findViewById(R.id.tvHello) + } +} + +class R { + object layout { + val activity_other = 100500 + } + + object id { + val tvHello = 0 + } +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/android/lintQuickfix/findViewById/simple.kt b/plugins/kotlin/idea/tests/testData/android/lintQuickfix/findViewById/simple.kt new file mode 100644 index 000000000000..788bc58c52cc --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/android/lintQuickfix/findViewById/simple.kt @@ -0,0 +1,28 @@ +// INTENTION_TEXT: Convert cast to findViewById with type parameter +// INSPECTION_CLASS: org.jetbrains.kotlin.android.inspection.TypeParameterFindViewByIdInspection + +import android.app.Activity +import android.os.Bundle +import android.widget.Button +import android.widget.TextView + + +class OtherActivity : Activity() { + + override fun onCreate(savedInstanceState: Bundle) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_other) + + val tvHello = findViewById(R.id.tvHello) as TextView + } +} + +class R { + object layout { + val activity_other = 100500 + } + + object id { + val tvHello = 0 + } +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/android/lintQuickfix/findViewById/simple.kt.expected b/plugins/kotlin/idea/tests/testData/android/lintQuickfix/findViewById/simple.kt.expected new file mode 100644 index 000000000000..fbf229a7ee80 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/android/lintQuickfix/findViewById/simple.kt.expected @@ -0,0 +1,28 @@ +// INTENTION_TEXT: Convert cast to findViewById with type parameter +// INSPECTION_CLASS: org.jetbrains.kotlin.android.inspection.TypeParameterFindViewByIdInspection + +import android.app.Activity +import android.os.Bundle +import android.widget.Button +import android.widget.TextView + + +class OtherActivity : Activity() { + + override fun onCreate(savedInstanceState: Bundle) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_other) + + val tvHello = findViewById(R.id.tvHello) + } +} + +class R { + object layout { + val activity_other = 100500 + } + + object id { + val tvHello = 0 + } +} \ No newline at end of file