Skip to content

Commit 4fe040e

Browse files
committed
Fixed several bugs in Android lint ApiDetector (KT-15002, KT-12024, KT-14737, KT-14825, KT-12023, KT-15018)
Merged IntelliJApiDetector to ApiDetector #KT-15002 Fixed #KT-12024 Fixed #KT-14737 Fixed #KT-14825 Fixed #KT-12023 Fixed #KT-15018 Fixed (cherry picked from commit e830e8b)
1 parent d0f1b81 commit 4fe040e

File tree

4 files changed

+529
-2050
lines changed

4 files changed

+529
-2050
lines changed

idea/testData/android/lint/apiCheck.kt

Lines changed: 178 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// INSPECTION_CLASS3: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintOverrideInspection
55

66
import android.animation.RectEvaluator
7+
import android.annotation.SuppressLint
78
import android.annotation.TargetApi
89
import org.w3c.dom.DOMError
910
import org.w3c.dom.DOMErrorHandler
@@ -14,6 +15,7 @@ import android.view.ViewGroup
1415
import android.view.ViewGroup.LayoutParams
1516
import android.app.Activity
1617
import android.app.ApplicationErrorReport
18+
import android.graphics.drawable.VectorDrawable
1719
import android.graphics.Path
1820
import android.graphics.PorterDuff
1921
import android.graphics.Rect
@@ -22,15 +24,15 @@ import android.widget.*
2224
import dalvik.bytecode.OpcodeInfo
2325

2426
import android.os.Build.VERSION
25-
import android.os.Build.VERSION.SDK_INT
27+
import <warning descr="Field requires API level 4 (current min is 1): `android.os.Build.VERSION#SDK_INT`">android.os.Build.VERSION.SDK_INT</warning>
2628
import android.os.Build.VERSION_CODES
2729
import android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH
2830
import android.os.Build.VERSION_CODES.JELLY_BEAN
2931
import android.os.Bundle
3032
import android.system.ErrnoException
3133
import android.widget.TextView
3234

33-
@Suppress("SENSELESS_COMPARISON", "UNUSED_EXPRESSION", "UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION")
35+
@Suppress("SENSELESS_COMPARISON", "UNUSED_EXPRESSION", "UsePropertyAccessSyntax", "UNUSED_VARIABLE", "unused", "UNUSED_PARAMETER", "DEPRECATION", "USELESS_CAST")
3436
class ApiCallTest: Activity() {
3537

3638
fun method(chronometer: Chronometer, locator: DOMLocator) {
@@ -39,38 +41,37 @@ class ApiCallTest: Activity() {
3941
// Ok
4042
Bundle().getInt("")
4143

42-
// Ok, this constant is inlined
43-
View.<warning descr="Field requires API level 16 (current min is 1): android.view.View#SYSTEM_UI_FLAG_FULLSCREEN">SYSTEM_UI_FLAG_FULLSCREEN</warning>
44+
View.<warning descr="Field requires API level 16 (current min is 1): `android.view.View#SYSTEM_UI_FLAG_FULLSCREEN`">SYSTEM_UI_FLAG_FULLSCREEN</warning>
4445

4546
// Virtual call
4647
<error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>() // API 11
4748
<error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">actionBar</error> // API 11
4849

4950
// Class references (no call or field access)
5051
val error: DOMError? = null // API 8
51-
val clz = DOMErrorHandler::class // API 8
52+
val clz = <error descr="Class requires API level 8 (current min is 1): org.w3c.dom.DOMErrorHandler">DOMErrorHandler::class</error> // API 8
5253

5354
// Method call
5455
chronometer.<error descr="Call requires API level 3 (current min is 1): android.widget.Chronometer#getOnChronometerTickListener">onChronometerTickListener</error> // API 3
5556

5657
// Inherited method call (from TextView
5758
chronometer.<error descr="Call requires API level 11 (current min is 1): android.widget.TextView#setTextIsSelectable">setTextIsSelectable</error>(true) // API 11
5859

59-
GridLayout::class
60+
<error descr="Class requires API level 14 (current min is 1): android.widget.GridLayout">GridLayout::class</error>
6061

6162
// Field access
62-
val field = OpcodeInfo.<warning descr="Field requires API level 11 (current min is 1): dalvik.bytecode.OpcodeInfo#MAXIMUM_VALUE">MAXIMUM_VALUE</warning> // API 11
63+
val field = OpcodeInfo.<warning descr="Field requires API level 11 (current min is 1): `dalvik.bytecode.OpcodeInfo#MAXIMUM_VALUE`">MAXIMUM_VALUE</warning> // API 11
6364

6465

6566
val fillParent = LayoutParams.FILL_PARENT // API 1
6667
// This is a final int, which means it gets inlined
6768
val matchParent = LayoutParams.MATCH_PARENT // API 8
6869
// Field access: non final
69-
val batteryInfo = report!!.<error descr="Field requires API level 14 (current min is 1): android.app.ApplicationErrorReport#batteryInfo">batteryInfo</error>
70+
val batteryInfo = report!!.<error descr="Field requires API level 14 (current min is 1): `android.app.ApplicationErrorReport#batteryInfo`">batteryInfo</error>
7071

7172
// Enum access
7273
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
73-
val mode = PorterDuff.Mode.<error descr="Field requires API level 11 (current min is 1): android.graphics.PorterDuff.Mode#OVERLAY">OVERLAY</error> // API 11
74+
val mode = PorterDuff.Mode.<error descr="Field requires API level 11 (current min is 1): `android.graphics.PorterDuff.Mode#OVERLAY`">OVERLAY</error> // API 11
7475
}
7576
}
7677

@@ -115,12 +116,6 @@ class ApiCallTest: Activity() {
115116
}
116117

117118
fun test(priority: Boolean, layout: ViewGroup) {
118-
if (layout is LinearLayout) {}
119-
layout as? LinearLayout
120-
121-
if (layout is GridLayout) {}
122-
layout as? GridLayout
123-
124119
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
125120
GridLayout(null).getOrientation(); // Not flagged
126121
} else {
@@ -250,25 +245,131 @@ class ApiCallTest: Activity() {
250245
//ERROR
251246
}
252247

253-
if (SDK_INT >= JELLY_BEAN && textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>()) {
248+
if (SDK_INT >= JELLY_BEAN && textView.isSuggestionsEnabled()) {
249+
//NO ERROR
250+
}
251+
252+
if (SDK_INT >= JELLY_BEAN && textView.isSuggestionsEnabled) {
254253
//NO ERROR
255254
}
256255

257-
if (SDK_INT >= JELLY_BEAN && textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>) {
256+
if (SDK_INT >= JELLY_BEAN && (textView.text != "" || textView.isSuggestionsEnabled)) {
258257
//NO ERROR
259258
}
260259

260+
if (SDK_INT < JELLY_BEAN && (textView.text != "" || textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>)) {
261+
//ERROR
262+
}
263+
261264
if (SDK_INT < JELLY_BEAN && textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>()) {
262265
//ERROR
263266
}
264267

265268
if (SDK_INT < JELLY_BEAN && textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>) {
266269
//ERROR
267270
}
271+
272+
if (SDK_INT < JELLY_BEAN || textView.isSuggestionsEnabled) {
273+
//NO ERROR
274+
}
275+
276+
if (SDK_INT > JELLY_BEAN || textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>) {
277+
//ERROR
278+
}
279+
280+
281+
// getActionBar() API 11
282+
if (SDK_INT <= 10 || getActionBar() == null) {
283+
//NO ERROR
284+
}
285+
286+
if (SDK_INT < 10 || <error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>() == null) {
287+
//ERROR
288+
}
289+
290+
if (SDK_INT < 11 || getActionBar() == null) {
291+
//NO ERROR
292+
}
293+
294+
if (SDK_INT != 11 || getActionBar() == null) {
295+
//NO ERROR
296+
}
297+
298+
if (SDK_INT != 12 || <error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>() == null) {
299+
//ERROR
300+
}
301+
302+
if (SDK_INT <= 11 || getActionBar() == null) {
303+
//NO ERROR
304+
}
305+
306+
if (SDK_INT < 12 || getActionBar() == null) {
307+
//NO ERROR
308+
}
309+
310+
if (SDK_INT <= 12 || getActionBar() == null) {
311+
//NO ERROR
312+
}
313+
314+
if (SDK_INT < 9 || <error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>() == null) {
315+
//ERROR
316+
}
317+
318+
if (SDK_INT <= 9 || <error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>() == null) {
319+
//ERROR
320+
}
321+
}
322+
323+
fun testReturn() {
324+
if (SDK_INT < 11) {
325+
return
326+
}
327+
328+
// No Error
329+
val actionBar = getActionBar()
330+
}
331+
332+
fun testThrow() {
333+
if (SDK_INT < 11) {
334+
throw IllegalStateException()
335+
}
336+
337+
// No Error
338+
val actionBar = getActionBar()
339+
}
340+
341+
fun testError() {
342+
if (SDK_INT < 11) {
343+
error("Api")
344+
}
345+
346+
// No Error
347+
val actionBar = getActionBar()
348+
}
349+
350+
fun testWithoutAnnotation(textView: TextView) {
351+
if (textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>()) {
352+
353+
}
354+
355+
if (textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>) {
356+
357+
}
268358
}
269359

270360
@TargetApi(JELLY_BEAN)
271-
fun testWithAnnotation(textView: TextView) {
361+
fun testWithTargetApiAnnotation(textView: TextView) {
362+
if (textView.isSuggestionsEnabled()) {
363+
//NO ERROR, annotation
364+
}
365+
366+
if (textView.isSuggestionsEnabled) {
367+
//NO ERROR, annotation
368+
}
369+
}
370+
371+
@SuppressLint("NewApi")
372+
fun testWithSuppressLintAnnotation(textView: TextView) {
272373
if (textView.isSuggestionsEnabled()) {
273374
//NO ERROR, annotation
274375
}
@@ -291,11 +392,70 @@ class ApiCallTest: Activity() {
291392
Path().<error descr="Call requires API level 21 (current min is 1): android.graphics.Path#addOval">addOval</error>(0f, 0f, 0f, 0f, Path.Direction.CW)
292393
}
293394

395+
// KT-14737 False error with short-circuit evaluation
396+
fun testShortCircuitEvaluation() {
397+
<error descr="Call requires API level 21 (current min is 1): android.content.Context#getDrawable">getDrawable</error>(0) // error here as expected
398+
if(Build.VERSION.SDK_INT >= 23
399+
&& null == getDrawable(0)) // error here should not occur
400+
{
401+
getDrawable(0) // no error here as expected
402+
}
403+
}
404+
405+
// KT-1482 Kotlin Lint: "Calling new methods on older versions" does not report call on receiver in extension function
406+
private fun Bundle.caseE1a() { <error descr="Call requires API level 18 (current min is 1): android.os.Bundle#getBinder">getBinder</error>("") }
407+
408+
private fun Bundle.caseE1c() { this.<error descr="Call requires API level 18 (current min is 1): android.os.Bundle#getBinder">getBinder</error>("") }
409+
410+
private fun caseE1b(bundle: Bundle) { bundle.<error descr="Call requires API level 18 (current min is 1): android.os.Bundle#getBinder">getBinder</error>("") }
411+
412+
// KT-12023 Kotlin Lint: Cast doesn't trigger minSdk error
413+
fun testCast(layout: ViewGroup) {
414+
if (layout is LinearLayout) {} // OK API 1
415+
layout as? LinearLayout // OK API 1
416+
layout as LinearLayout // OK API 1
417+
418+
if (layout !is GridLayout) {} // TODO: should be error, fixed in uast > 1.0.8
419+
layout as? GridLayout // TODO: should be error, fixed in uast > 1.0.8
420+
layout as GridLayout // TODO: should be error, fixed in uast > 1.0.8
421+
422+
val grid = layout as? GridLayout // TODO: should be error, fixed in uast > 1.0.8
423+
val linear = layout as LinearLayout // OK API 1
424+
}
425+
426+
// TODO: should be error
427+
class ErrorVectorDravable : VectorDrawable()
428+
429+
@TargetApi(21)
430+
class MyVectorDravable : VectorDrawable()
431+
432+
fun testTypes() {
433+
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(this)
434+
val c = <error descr="Class requires API level 21 (current min is 1): android.graphics.drawable.VectorDrawable">VectorDrawable::class</error>.java
435+
}
436+
437+
fun testCallWithApiAnnotation(textView: TextView) {
438+
<error descr="Call requires API level 21 (current min is 1): ApiCallTest.MyVectorDravable#MyVectorDravable">MyVectorDravable</error>()
439+
<error descr="Call requires API level 16 (current min is 1): ApiCallTest#testWithTargetApiAnnotation">testWithTargetApiAnnotation</error>(textView)
440+
}
441+
442+
companion object : Activity() {
443+
fun test() {
444+
<error descr="Call requires API level 21 (current min is 1): android.content.Context#getDrawable">getDrawable</error>(0)
445+
}
446+
}
447+
294448
// Return type
295449
internal // API 14
296450
val gridLayout: GridLayout?
297451
get() = null
298452

299453
private val report: ApplicationErrorReport?
300454
get() = null
455+
}
456+
457+
object O: Activity() {
458+
fun test() {
459+
<error descr="Call requires API level 21 (current min is 1): android.content.Context#getDrawable">getDrawable</error>(0)
460+
}
301461
}

0 commit comments

Comments
 (0)