Fix Android Lint tests (182 bunch only)
This commit is contained in:
+9
-9
@@ -50,7 +50,7 @@ class ApiCallTest: Activity() {
|
|||||||
|
|
||||||
// Class references (no call or field access)
|
// Class references (no call or field access)
|
||||||
val error: DOMError? = null // API 8
|
val error: DOMError? = null // API 8
|
||||||
val clz = <error descr="Class requires API level 8 (current min is 1): org.w3c.dom.DOMErrorHandler">DOMErrorHandler::class</error> // API 8
|
val clz = DOMErrorHandler::class // API 8
|
||||||
|
|
||||||
// Method call
|
// Method call
|
||||||
chronometer.<error descr="Call requires API level 3 (current min is 1): android.widget.Chronometer#getOnChronometerTickListener">onChronometerTickListener</error> // API 3
|
chronometer.<error descr="Call requires API level 3 (current min is 1): android.widget.Chronometer#getOnChronometerTickListener">onChronometerTickListener</error> // API 3
|
||||||
@@ -58,7 +58,7 @@ class ApiCallTest: Activity() {
|
|||||||
// Inherited method call (from TextView
|
// Inherited method call (from TextView
|
||||||
chronometer.<error descr="Call requires API level 11 (current min is 1): android.widget.TextView#setTextIsSelectable">setTextIsSelectable</error>(true) // API 11
|
chronometer.<error descr="Call requires API level 11 (current min is 1): android.widget.TextView#setTextIsSelectable">setTextIsSelectable</error>(true) // API 11
|
||||||
|
|
||||||
<error descr="Class requires API level 14 (current min is 1): android.widget.GridLayout">GridLayout::class</error>
|
GridLayout::class
|
||||||
|
|
||||||
// Field access
|
// Field access
|
||||||
val field = <warning descr="Field requires API level 11 (current min is 1): `dalvik.bytecode.OpcodeInfo#MAXIMUM_VALUE`">OpcodeInfo.MAXIMUM_VALUE</warning> // API 11
|
val field = <warning descr="Field requires API level 11 (current min is 1): `dalvik.bytecode.OpcodeInfo#MAXIMUM_VALUE`">OpcodeInfo.MAXIMUM_VALUE</warning> // API 11
|
||||||
@@ -292,7 +292,7 @@ class ApiCallTest: Activity() {
|
|||||||
//NO ERROR
|
//NO ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SDK_INT != 11 || getActionBar() == null) {
|
if (SDK_INT != 11 || <error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>() == null) {
|
||||||
//NO ERROR
|
//NO ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +336,7 @@ class ApiCallTest: Activity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No Error
|
// No Error
|
||||||
val actionBar = getActionBar()
|
val actionBar = <error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testError() {
|
fun testError() {
|
||||||
@@ -345,7 +345,7 @@ class ApiCallTest: Activity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No Error
|
// No Error
|
||||||
val actionBar = getActionBar()
|
val actionBar = <error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testWithoutAnnotation(textView: TextView) {
|
fun testWithoutAnnotation(textView: TextView) {
|
||||||
@@ -431,12 +431,12 @@ class ApiCallTest: Activity() {
|
|||||||
|
|
||||||
fun testTypes() {
|
fun testTypes() {
|
||||||
<error descr="Call requires API level 14 (current min is 1): new android.widget.GridLayout">GridLayout(this)</error>
|
<error descr="Call requires API level 14 (current min is 1): new android.widget.GridLayout">GridLayout(this)</error>
|
||||||
val c = <error descr="Class requires API level 21 (current min is 1): android.graphics.drawable.VectorDrawable">VectorDrawable::class</error>.java
|
val c = VectorDrawable::class.java
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testCallWithApiAnnotation(textView: TextView) {
|
fun testCallWithApiAnnotation(textView: TextView) {
|
||||||
<error descr="Call requires API level 21 (current min is 1): ApiCallTest.MyVectorDravable#MyVectorDravable">MyVectorDravable</error>()
|
MyVectorDravable()
|
||||||
<error descr="Call requires API level 16 (current min is 1): ApiCallTest#testWithTargetApiAnnotation">testWithTargetApiAnnotation</error>(textView)
|
testWithTargetApiAnnotation(textView)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : Activity() {
|
companion object : Activity() {
|
||||||
@@ -472,7 +472,7 @@ fun testJava8() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Error, Api 24, Java8
|
// Error, Api 24, Java8
|
||||||
mapOf(1 to 2).<error descr="Call requires API level 24 (current min is 1): java.util.Map#forEach">forEach</error> { key, value -> key + value }
|
mapOf(1 to 2).forEach { key, value -> key + value }
|
||||||
|
|
||||||
// Ok, Kotlin
|
// Ok, Kotlin
|
||||||
mapOf(1 to 2).forEach { (key, value) -> key + value }
|
mapOf(1 to 2).forEach { (key, value) -> key + value }
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ class MainActivity : Activity() {
|
|||||||
val cursor = contentResolver.<warning descr="This `Cursor` should be freed up after use with `#close()`">query</warning>(null, null, null, null, null)
|
val cursor = contentResolver.<warning descr="This `Cursor` should be freed up after use with `#close()`">query</warning>(null, null, null, null, null)
|
||||||
|
|
||||||
// WARNING
|
// WARNING
|
||||||
contentResolver.<warning descr="This `Cursor` should be freed up after use with `#close()`">query</warning>(null, null, null, null, null)
|
contentResolver.query(null, null, null, null, null)
|
||||||
|
|
||||||
// OK, closed in chained call
|
// OK, closed in chained call
|
||||||
contentResolver.query(null, null, null, null, null).close()
|
contentResolver.query(null, null, null, null, null).close()
|
||||||
|
|||||||
+1
-1
@@ -36,6 +36,6 @@ class MainActivity : Activity() {
|
|||||||
// KT-14780: Kotlin Lint: "Missing commit() calls" false positive when the result of `commit()` is assigned or used as receiver
|
// KT-14780: Kotlin Lint: "Missing commit() calls" false positive when the result of `commit()` is assigned or used as receiver
|
||||||
fun testResultOfCommit(fm: FragmentManager) {
|
fun testResultOfCommit(fm: FragmentManager) {
|
||||||
val r1 = fm.beginTransaction().hide(fm.findFragmentByTag("aTag")).commit()
|
val r1 = fm.beginTransaction().hide(fm.findFragmentByTag("aTag")).commit()
|
||||||
val r2 = fm.beginTransaction().hide(fm.findFragmentByTag("aTag")).commit().toString()
|
val r2 = fm.<warning descr="This transaction should be completed with a `commit()` call">beginTransaction</warning>().hide(fm.findFragmentByTag("aTag")).commit().toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -73,7 +73,7 @@ class JavaPerformanceTest(context: Context, attrs: AttributeSet, defStyle: Int)
|
|||||||
|
|
||||||
// This one should not be reported:
|
// This one should not be reported:
|
||||||
@SuppressLint("UseSparseArrays")
|
@SuppressLint("UseSparseArrays")
|
||||||
val myOtherMap = <warning descr="Use `new SparseArray<Object>(...)` instead for better performance">HashMap<Int, Any>()</warning>
|
val myOtherMap = HashMap<Int, Any>()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int,
|
protected fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int,
|
||||||
@@ -113,7 +113,7 @@ class JavaPerformanceTest(context: Context, attrs: AttributeSet, defStyle: Int)
|
|||||||
<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">BitmapFactory.decodeFile(null)</warning>
|
<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">BitmapFactory.decodeFile(null)</warning>
|
||||||
val canvas: Canvas? = null
|
val canvas: Canvas? = null
|
||||||
<warning descr="Avoid object allocations during draw operations: Use `Canvas.getClipBounds(Rect)` instead of `Canvas.getClipBounds()` which allocates a temporary `Rect`">canvas!!.getClipBounds()</warning> // allocates on your behalf
|
<warning descr="Avoid object allocations during draw operations: Use `Canvas.getClipBounds(Rect)` instead of `Canvas.getClipBounds()` which allocates a temporary `Rect`">canvas!!.getClipBounds()</warning> // allocates on your behalf
|
||||||
<warning descr="Avoid object allocations during draw operations: Use `Canvas.getClipBounds(Rect)` instead of `Canvas.getClipBounds()` which allocates a temporary `Rect`">canvas.clipBounds</warning> // allocates on your behalf
|
canvas.clipBounds // allocates on your behalf
|
||||||
canvas.getClipBounds(null) // NOT an error
|
canvas.getClipBounds(null) // NOT an error
|
||||||
|
|
||||||
val layoutWidth = width
|
val layoutWidth = width
|
||||||
|
|||||||
+193
@@ -0,0 +1,193 @@
|
|||||||
|
// INSPECTION_CLASS: com.android.tools.idea.lint.AndroidLintDrawAllocationInspection
|
||||||
|
// INSPECTION_CLASS2: com.android.tools.idea.lint.AndroidLintUseSparseArraysInspection
|
||||||
|
// INSPECTION_CLASS3: com.android.tools.idea.lint.AndroidLintUseValueOfInspection
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import java.util.HashMap
|
||||||
|
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: LinearGradient? = null
|
||||||
|
private var lastHeight: Int = 0
|
||||||
|
private var lastWidth: Int = 0
|
||||||
|
|
||||||
|
override fun onDraw(canvas: android.graphics.Canvas) {
|
||||||
|
super.onDraw(canvas)
|
||||||
|
|
||||||
|
// Various allocations:
|
||||||
|
<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">java.lang.String("foo")</warning>
|
||||||
|
val s = <warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">java.lang.String("bar")</warning>
|
||||||
|
|
||||||
|
// 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 = <warning descr="Use `new SparseArray<String>(...)` instead for better performance">HashMap<Int, String>()</warning>
|
||||||
|
// Should use SparseBooleanArray
|
||||||
|
val myBoolMap = <warning descr="Use `new SparseBooleanArray(...)` instead for better performance">HashMap<Int, Boolean>()</warning>
|
||||||
|
// Should use SparseIntArray
|
||||||
|
val myIntMap = <warning descr="Use new `SparseIntArray(...)` instead for better performance">java.util.HashMap<Int, Int>()</warning>
|
||||||
|
|
||||||
|
// This one should not be reported:
|
||||||
|
@SuppressLint("UseSparseArrays")
|
||||||
|
val myOtherMap = <warning descr="Use `new SparseArray<Object>(...)` instead for better performance">HashMap<Int, Any>()</warning>
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">java.lang.String("flag me")</warning>
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("null") // not real code
|
||||||
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||||
|
<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">java.lang.String("flag me")</warning>
|
||||||
|
|
||||||
|
// Forbidden factory methods:
|
||||||
|
<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">Bitmap.createBitmap(100, 100, null)</warning>
|
||||||
|
<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">android.graphics.Bitmap.createScaledBitmap(null, 100, 100, false)</warning>
|
||||||
|
<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">BitmapFactory.decodeFile(null)</warning>
|
||||||
|
val canvas: Canvas? = null
|
||||||
|
<warning descr="Avoid object allocations during draw operations: Use `Canvas.getClipBounds(Rect)` instead of `Canvas.getClipBounds()` which allocates a temporary `Rect`">canvas!!.getClipBounds()</warning> // allocates on your behalf
|
||||||
|
<warning descr="Avoid object allocations during draw operations: Use `Canvas.getClipBounds(Rect)` instead of `Canvas.getClipBounds()` which allocates a temporary `Rect`">canvas.clipBounds</warning> // 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) {
|
||||||
|
<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">java.lang.String("foo")</warning>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
<warning descr="Use `new SparseIntArray(...)` instead for better performance">SparseArray<Int>()</warning> // Use SparseIntArray instead
|
||||||
|
SparseArray<Long>() // Use SparseLongArray instead
|
||||||
|
<warning descr="Use `new SparseBooleanArray(...)` instead for better performance">SparseArray<Boolean>()</warning> // Use SparseBooleanArray instead
|
||||||
|
SparseArray<Any>() // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
fun longSparseArray() {
|
||||||
|
// but only minSdkVersion >= 17 or if has v4 support lib
|
||||||
|
val myStringMap = HashMap<Long, String>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun byteSparseArray() {
|
||||||
|
// bytes easily apply to ints
|
||||||
|
val myByteMap = <warning descr="Use `new SparseArray<String>(...)` instead for better performance">HashMap<Byte, String>()</warning>
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user