Lint: Fix diagnostic tests

This commit is contained in:
Yan Zhulanow
2016-10-13 21:38:14 +03:00
committed by Yan Zhulanow
parent 565ca0f7a3
commit 7404b91cb3
13 changed files with 500 additions and 355 deletions
+2 -2
View File
@@ -8,8 +8,8 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="guava" level="project" />
<orderEntry type="module" module-name="uast-common" />
<orderEntry type="module" module-name="uast-java" />
<orderEntry type="module" module-name="uast-common" exported="" />
<orderEntry type="module" module-name="uast-java" exported="" />
<orderEntry type="library" name="android-plugin" level="project" />
<orderEntry type="library" name="intellij-core" level="project" />
<orderEntry type="module" module-name="android-annotations" />
File diff suppressed because it is too large Load Diff
@@ -28,12 +28,7 @@ import com.android.tools.klint.detector.api.Scope;
import com.android.tools.klint.detector.api.Severity;
import com.intellij.psi.PsiMethod;
import org.jetbrains.uast.UCallExpression;
import org.jetbrains.uast.UExpression;
import org.jetbrains.uast.ULiteralExpression;
import org.jetbrains.uast.UMethod;
import org.jetbrains.uast.UReturnExpression;
import org.jetbrains.uast.UastUtils;
import org.jetbrains.uast.*;
import org.jetbrains.uast.visitor.AbstractUastVisitor;
import org.jetbrains.uast.visitor.UastVisitor;
@@ -90,32 +85,34 @@ public class ToastDetector extends Detector implements Detector.UastScanner {
"duration value is not supported");
}
}
UMethod surroundingMethod = UastUtils.getContainingUMethod(call);
if (surroundingMethod == null) {
UElement surroundingDeclaration = UastUtils.getParentOfType(
call, true,
UMethod.class, UBlockExpression.class, ULambdaExpression.class);
if (surroundingDeclaration == null) {
return;
}
ShowFinder finder = new ShowFinder(call);
surroundingMethod.getUastBody().accept(finder);
surroundingDeclaration.accept(finder);
if (!finder.isShowCalled()) {
context.report(ISSUE, call, context.getUastNameLocation(call),
"Toast created but not shown: did you forget to call `show()` ?");
"Toast created but not shown: did you forget to call `show()` ?");
}
}
private static class ShowFinder extends AbstractUastVisitor {
/** The target makeText call */
private final UExpression mTarget;
private final UCallExpression mTarget;
/** Whether we've found the show method */
private boolean mFound;
/** Whether we've seen the target makeText node yet */
private boolean mSeenTarget;
private ShowFinder(UCallExpression target) {
mTarget = UastUtils.getQualifiedParentOrThis(target);
mTarget = target;
}
@Override
@@ -123,14 +120,14 @@ public class ToastDetector extends Detector implements Detector.UastScanner {
if (node.equals(mTarget)) {
mSeenTarget = true;
} else {
if ((mTarget.equals(node.getReceiver()))
&& "show".equals(node.getMethodName())) {
if ((mSeenTarget || mTarget.equals(node.getReceiver()))
&& "show".equals(node.getMethodName())) {
// TODO: Do more flow analysis to see whether we're really calling show
// on the right type of object?
mFound = true;
}
}
return super.visitCallExpression(node);
}
@@ -140,7 +137,7 @@ public class ToastDetector extends Detector implements Detector.UastScanner {
// If you just do "return Toast.makeText(...) don't warn
mFound = true;
}
return super.visitReturnExpression(node);
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.uast
import org.jetbrains.android.inspections.klint.AndroidLintInspectionBase
import org.jetbrains.kotlin.android.KotlinAndroidTestCase
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.test.InTextDirectivesUtils.findStringWithPrefixes
@@ -27,7 +28,7 @@ abstract class AbstractKotlinLintTest : KotlinAndroidTestCase() {
override fun setUp() {
super.setUp()
ConfigLibraryUtil.configureKotlinRuntime(myModule)
// AndroidLintInspectionBase.invalidateInspectionShortName2IssueMap()
AndroidLintInspectionBase.invalidateInspectionShortName2IssueMap()
}
override fun tearDown() {
@@ -45,29 +46,28 @@ abstract class AbstractKotlinLintTest : KotlinAndroidTestCase() {
inspectionClassNames += className
}
//TODO
// myFixture.enableInspections(*inspectionClassNames.map { className ->
// val inspectionClass = Class.forName(className)
// inspectionClass.newInstance() as AndroidLintInspectionBase
// }.toTypedArray())
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)
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/"
+73 -74
View File
@@ -1,4 +1,4 @@
// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection
<error descr="The SDK platform-tools version (23) is too old to check APIs compiled with API 23; please update">// INSPECTION_CLASS: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintNewApiInspection</error>
// INSPECTION_CLASS2: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintInlinedApiInspection
// INSPECTION_CLASS3: org.jetbrains.android.inspections.klint.AndroidLintInspectionToolProvider$AndroidKLintOverrideInspection
@@ -31,52 +31,51 @@ import android.widget.TextView
class ApiCallTest: Activity() {
fun method(chronometer: Chronometer, locator: DOMLocator) {
chronometer.<error descr="Call requires API level 16 (current min is 1): `setBackground`">setBackground(null)</error>
chronometer.<error descr="Call requires API level 16 (current min is 1): android.view.View#setBackground">setBackground</error>(null)
// Ok
Bundle().getInt("")
// Ok, this constant is inlined
View.SYSTEM_UI_FLAG_FULLSCREEN
View.<warning descr="Field requires API level 16 (current min is 1): android.view.View#SYSTEM_UI_FLAG_FULLSCREEN">SYSTEM_UI_FLAG_FULLSCREEN</warning>
// Virtual call
<error descr="Call requires API level 11 (current min is 1): `getActionBar`">getActionBar()</error> // API 11
<error descr="Call requires API level 11 (current min is 1): `getActionBar`">actionBar</error> // API 11
<error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">getActionBar</error>() // API 11
<error descr="Call requires API level 11 (current min is 1): android.app.Activity#getActionBar">actionBar</error> // API 11
// Class references (no call or field access)
val error: DOMError? = null // API 8
val clz = DOMErrorHandler::class // API 8
// Method call
chronometer.<error descr="Call requires API level 3 (current min is 1): `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
// Inherited method call (from TextView
chronometer.<error descr="Call requires API level 11 (current min is 1): `setTextIsSelectable`">setTextIsSelectable(true)</error> // API 11
chronometer.<error descr="Call requires API level 11 (current min is 1): android.widget.TextView#setTextIsSelectable">setTextIsSelectable</error>(true) // API 11
// TODO: fix UClassLiteralExpression and uncomment, must be: error descr="Class requires API level 14 (current min is 1): `GridLayout`"
GridLayout::class
// Field access
val field = OpcodeInfo.<error descr="Field requires API level 11 (current min is 1): `MAXIMUM_VALUE`">MAXIMUM_VALUE</error> // API 11
val field = OpcodeInfo.<warning descr="Field requires API level 11 (current min is 1): dalvik.bytecode.OpcodeInfo#MAXIMUM_VALUE">MAXIMUM_VALUE</warning> // 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!!.<error descr="Field requires API level 14 (current min is 1): `batteryInfo`">batteryInfo</error>
val batteryInfo = report!!.<error descr="Field requires API level 14 (current min is 1): android.app.ApplicationErrorReport#batteryInfo">batteryInfo</error>
// Enum access
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> <= Build.VERSION_CODES.LOLLIPOP) {
val mode = PorterDuff.Mode.<error descr="Field requires API level 11 (current min is 1): `OVERLAY`">OVERLAY</error> // API 11
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
val mode = PorterDuff.Mode.<error descr="Field requires API level 11 (current min is 1): android.graphics.PorterDuff.Mode#OVERLAY">OVERLAY</error> // API 11
}
}
fun test(rect: Rect) {
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.LOLLIPOP) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
RectEvaluator(rect); // OK
}
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.LOLLIPOP) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (rect != null) {
RectEvaluator(rect); // OK
}
@@ -84,183 +83,183 @@ class ApiCallTest: Activity() {
}
fun test2(rect: Rect) {
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.LOLLIPOP) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
RectEvaluator(rect); // OK
}
}
fun test3(rect: Rect) {
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.GINGERBREAD) {
<error descr="Class requires API level 18 (current min is 1): `RectEvaluator`">RectEvaluator()</error>; // ERROR
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
<error descr="Call requires API level 18 (current min is 1): android.animation.RectEvaluator#RectEvaluator">RectEvaluator</error>(); // ERROR
}
}
fun test4(rect: Rect) {
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.LOLLIPOP) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
System.out.println("Something");
RectEvaluator(rect); // OK
} else {
<error descr="Class requires API level 18 (current min is 1): `RectEvaluator`">RectEvaluator(rect)</error>; // ERROR
<error descr="Call requires API level 21 (current min is 1): android.animation.RectEvaluator#RectEvaluator">RectEvaluator</error>(rect); // ERROR
}
}
fun test5(rect: Rect) {
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.CUPCAKE) {
<error descr="Class requires API level 18 (current min is 1): `RectEvaluator`">RectEvaluator(rect)</error>; // ERROR
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
<error descr="Call requires API level 21 (current min is 1): android.animation.RectEvaluator#RectEvaluator">RectEvaluator</error>(rect); // ERROR
} else {
RectEvaluator(rect); // ERROR
<error descr="Call requires API level 21 (current min is 1): android.animation.RectEvaluator#RectEvaluator">RectEvaluator</error>(rect); // ERROR
}
}
fun test(priority: Boolean, layout: ViewGroup) {
if (layout is LinearLayout) {}
layout as? LinearLayout
if (layout is <error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout</error>) {}
layout as? <error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout</error>
if (android.os.Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
if (layout is GridLayout) {}
layout as? GridLayout
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>.<error descr="Call requires API level 14 (current min is 1): `getOrientation`">getOrientation()</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>.<error descr="Call requires API level 14 (current min is 1): `getOrientation`">getOrientation()</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
if (<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= ICE_CREAM_SANDWICH) {
if (SDK_INT >= ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>.<error descr="Call requires API level 14 (current min is 1): `getOrientation`">getOrientation()</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>.<error descr="Call requires API level 14 (current min is 1): `getOrientation`">getOrientation()</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>.<error descr="Call requires API level 14 (current min is 1): `getOrientation`">getOrientation()</error>; // Flagged
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
} else {
GridLayout(null).getOrientation(); // Not flagged
}
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= 14) {
if (Build.VERSION.SDK_INT >= 14) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>.<error descr="Call requires API level 14 (current min is 1): `getOrientation`">getOrientation()</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
if (VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= VERSION_CODES.ICE_CREAM_SANDWICH) {
if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>.<error descr="Call requires API level 14 (current min is 1): `getOrientation`">getOrientation()</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
// Nested conditionals
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.HONEYCOMB) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (priority) {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>.<error descr="Call requires API level 14 (current min is 1): `getOrientation`">getOrientation()</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>.<error descr="Call requires API level 14 (current min is 1): `getOrientation`">getOrientation()</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
} else {
GridLayout(null).getOrientation(); // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
}
// Nested conditionals 2
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.JELLY_BEAN) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (priority) {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>.<error descr="Call requires API level 14 (current min is 1): `getOrientation`">getOrientation()</error>; // Not flagged
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>.<error descr="Call requires API level 14 (current min is 1): `getOrientation`">getOrientation()</error>; // Not flagged
GridLayout(null).getOrientation(); // Not flagged
}
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
}
fun test2(priority: Boolean) {
if (android.os.Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= VERSION_CODES.JELLY_BEAN) {
if (android.os.Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (android.os.Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= 16) {
if (android.os.Build.VERSION.SDK_INT >= 16) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (android.os.Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= 13) {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>.<error descr="Call requires API level 14 (current min is 1): `getOrientation`">getOrientation()</error>; // Flagged
if (android.os.Build.VERSION.SDK_INT >= 13) {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null).<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#getOrientation">getOrientation</error>(); // Flagged
} else {
GridLayout(null); // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.JELLY_BEAN) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= JELLY_BEAN) {
if (SDK_INT >= JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.JELLY_BEAN) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> < Build.VERSION_CODES.JELLY_BEAN) {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>; // Flagged
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
} else {
GridLayout(null).getOrientation(); // Not flagged
}
if (Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= 16) {
if (Build.VERSION.SDK_INT >= 16) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
if (VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= VERSION_CODES.JELLY_BEAN) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
GridLayout(null).getOrientation(); // Not flagged
} else {
<error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout(null)</error>; // Flagged
<error descr="Call requires API level 14 (current min is 1): android.widget.GridLayout#GridLayout">GridLayout</error>(null); // Flagged
}
}
fun test(textView: TextView) {
if (textView.<error descr="Call requires API level 14 (current min is 1): `isSuggestionsEnabled`">isSuggestionsEnabled()</error>) {
if (textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>()) {
//ERROR
}
if (textView.<error descr="Call requires API level 14 (current min is 1): `isSuggestionsEnabled`">isSuggestionsEnabled</error>) {
if (textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>) {
//ERROR
}
if (<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= JELLY_BEAN && textView.isSuggestionsEnabled()) {
if (SDK_INT >= JELLY_BEAN && textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>()) {
//NO ERROR
}
if (<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= JELLY_BEAN && textView.isSuggestionsEnabled) {
if (SDK_INT >= JELLY_BEAN && textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>) {
//NO ERROR
}
if (<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> < JELLY_BEAN && textView.<error descr="Call requires API level 14 (current min is 1): `isSuggestionsEnabled`">isSuggestionsEnabled()</error>) {
if (SDK_INT < JELLY_BEAN && textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>()) {
//ERROR
}
if (<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> < JELLY_BEAN && textView.<error descr="Call requires API level 14 (current min is 1): `isSuggestionsEnabled`">isSuggestionsEnabled</error>) {
if (SDK_INT < JELLY_BEAN && textView.<error descr="Call requires API level 14 (current min is 1): android.widget.TextView#isSuggestionsEnabled">isSuggestionsEnabled</error>) {
//ERROR
}
}
+3 -3
View File
@@ -73,7 +73,7 @@ class JavaPerformanceTest(context: Context, attrs: AttributeSet, defStyle: Int)
// This one should not be reported:
@SuppressLint("UseSparseArrays")
val myOtherMap = HashMap<Int, Any>()
val myOtherMap = <warning descr="Use `new SparseArray<Object>(...)` instead for better performance">HashMap<Int, Any>()</warning>
}
protected fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int,
@@ -120,8 +120,8 @@ class JavaPerformanceTest(context: Context, attrs: AttributeSet, defStyle: Int)
val layoutHeight = height
if (mAllowCrop && (mOverlay == null || mOverlay!!.width != layoutWidth ||
mOverlay!!.height != layoutHeight)) {
mOverlay = Bitmap.<warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">createBitmap(layoutWidth, layoutHeight, Bitmap.Config.ARGB_8888)</warning>
mOverlayCanvas = <warning descr="Avoid object allocations during draw/layout operations (preallocate and reuse instead)">Canvas(mOverlay!!)</warning>
mOverlay = Bitmap.createBitmap(layoutWidth, layoutHeight, Bitmap.Config.ARGB_8888)
mOverlayCanvas = Canvas(mOverlay!!)
}
if (widthMeasureSpec == 42) {
+8 -8
View File
@@ -15,8 +15,8 @@ class LogTest {
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.<warning descr="The log call Log.i(...) should be conditional: surround with `if (Log.isLoggable(...))` or `if (BuildConfig.DEBUG) { ... }`">i(TAG1, "message" + m)</warning> // error: unconditional w/ computation
Log.<warning descr="The log call Log.i(...) should be conditional: surround with `if (Log.isLoggable(...))` or `if (BuildConfig.DEBUG) { ... }`">i(TAG1, toString())</warning> // 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
@@ -26,11 +26,11 @@ class LogTest {
}
fun checkWrongTag(tag: String) {
if (Log.isLoggable(<error descr="Mismatched tags: the `d()` and `isLoggable()` calls typically should pass the same tag: `MyTag1` versus `MyTag2` (Conflicting tag)">TAG1</error>, Log.DEBUG)) {
Log.d(<error descr="Mismatched tags: the `d()` and `isLoggable()` calls typically should pass the same tag: `MyTag1` versus `MyTag2`">TAG2</error>, "message") // warn: mismatched tags!
if (Log.isLoggable(<error descr="Mismatched tags: the `d()` and `isLoggable()` calls typically should pass the same tag: `getTAG1` versus `getTAG2` (Conflicting tag)">TAG1</error>, Log.DEBUG)) {
Log.d(<error descr="Mismatched tags: the `d()` and `isLoggable()` calls typically should pass the same tag: `getTAG1` versus `getTAG2`">TAG2</error>, "message") // warn: mismatched tags!
}
if (Log.isLoggable("<error descr="Mismatched tags: the `d()` and `isLoggable()` calls typically should pass the same tag: `my_tag` versus `other_tag` (Conflicting tag)">my_tag</error>", Log.DEBUG)) {
Log.d("<error descr="Mismatched tags: the `d()` and `isLoggable()` calls typically should pass the same tag: `my_tag` versus `other_tag`">other_tag</error>", "message") // warn: mismatched tags!
if (Log.isLoggable("<error descr="Mismatched tags: the `d()` and `isLoggable()` calls typically should pass the same tag: `\"my_tag\"` versus `\"other_tag\"` (Conflicting tag)">my_tag</error>", Log.DEBUG)) {
Log.d("<error descr="Mismatched tags: the `d()` and `isLoggable()` calls typically should pass the same tag: `\"my_tag\"` versus `\"other_tag\"`">other_tag</error>", "message") // warn: mismatched tags!
}
if (Log.isLoggable("my_tag", Log.DEBUG)) {
Log.d("my_tag", "message") // ok: strings equal
@@ -73,9 +73,9 @@ class LogTest {
if (Log.isLoggable(TAG1, <error descr="Mismatched logging levels: when checking `isLoggable` level `DEBUG`, the corresponding log call should be `Log.d`, not `Log.v` (Conflicting tag)">Log.DEBUG</error>)) {
Log.<error descr="Mismatched logging levels: when checking `isLoggable` level `DEBUG`, the corresponding log call should be `Log.d`, not `Log.v`">v</error>(TAG1, "message") // warn: wrong level
}
if (Log.isLoggable(TAG1, DEBUG)) {
if (Log.isLoggable(TAG1, <error descr="Mismatched logging levels: when checking `isLoggable` level `DEBUG`, the corresponding log call should be `Log.d`, not `Log.v` (Conflicting tag)">DEBUG</error>)) {
// static import of level
Log.v(TAG1, "message") // warn: wrong level
Log.<error descr="Mismatched logging levels: when checking `isLoggable` level `DEBUG`, the corresponding log call should be `Log.d`, not `Log.v`">v</error>(TAG1, "message") // warn: wrong level
}
if (Log.isLoggable(TAG1, <error descr="Mismatched logging levels: when checking `isLoggable` level `VERBOSE`, the corresponding log call should be `Log.v`, not `Log.d` (Conflicting tag)">Log.VERBOSE</error>)) {
Log.<error descr="Mismatched logging levels: when checking `isLoggable` level `VERBOSE`, the corresponding log call should be `Log.v`, not `Log.d`">d</error>(TAG1, "message") // warn? verbose is a lower logging level, which includes debug
+1 -1
View File
@@ -55,7 +55,7 @@ class RecyclerViewScrollPosition(val position: Int, val topOffset: Int): Parcela
}
}
class <error>RecyclerViewScrollPositionWithoutJvmF</error>(val position: Int, val topOffset: Int): Parcelable {
class RecyclerViewScrollPositionWithoutJvmF(val position: Int, val topOffset: Int): Parcelable {
override fun describeContents(): Int = 0
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeInt(position)
@@ -5,5 +5,5 @@ import android.database.sqlite.SQLiteDatabase
fun test(db: SQLiteDatabase) {
val <warning descr="[UNUSED_VARIABLE] Variable 'a' is never used">a</warning>: String = <error descr="[CONSTANT_EXPECTED_TYPE_MISMATCH] The integer literal does not conform to the expected type String">1</error>
db.<warning descr="Using column type STRING; did you mean to use TEXT? (STRING is a numeric type and its value can be adjusted; for example,strings that look like integers can drop leading zeroes. See issue explanation for details.)">execSQL("CREATE TABLE COMPANY(NAME STRING)")</warning>
db.<warning descr="Using column type STRING; did you mean to use TEXT? (STRING is a numeric type and its value can be adjusted; for example, strings that look like integers can drop leading zeroes. See issue explanation for details.)">execSQL("CREATE TABLE COMPANY(NAME STRING)")</warning>
}
+1 -1
View File
@@ -3,5 +3,5 @@
import android.database.sqlite.SQLiteDatabase
fun test(db: SQLiteDatabase) {
db.<warning descr="Using column type STRING; did you mean to use TEXT? (STRING is a numeric type and its value can be adjusted; for example,strings that look like integers can drop leading zeroes. See issue explanation for details.)">execSQL("CREATE TABLE COMPANY(NAME STRING)")</warning>
db.<warning descr="Using column type STRING; did you mean to use TEXT? (STRING is a numeric type and its value can be adjusted; for example, strings that look like integers can drop leading zeroes. See issue explanation for details.)">execSQL("CREATE TABLE COMPANY(NAME STRING)")</warning>
}
+5 -5
View File
@@ -24,7 +24,7 @@ class ToastTest(context: Context) : Activity() {
}
Runnable {
Toast.<warning descr="Toast created but not shown: did you forget to call `show()` ?">makeText(context, "foo", Toast.LENGTH_LONG)</warning>
Toast.<warning descr="Toast created but not shown: did you forget to call `show()` ?">makeText</warning>(context, "foo", Toast.LENGTH_LONG)
}
}
@@ -45,13 +45,13 @@ class ToastTest(context: Context) : Activity() {
private fun broken(context: Context) {
// Errors
Toast.<warning descr="Toast created but not shown: did you forget to call `show()` ?">makeText(context, "foo", Toast.LENGTH_LONG)</warning>
val toast = Toast.<warning descr="Toast created but not shown: did you forget to call `show()` ?">makeText(context, R.string.app_name, <warning descr="Expected duration `Toast.LENGTH_SHORT` or `Toast.LENGTH_LONG`, a custom duration value is not supported">5000</warning>)</warning>
Toast.<warning descr="Toast created but not shown: did you forget to call `show()` ?">makeText</warning>(context, "foo", Toast.LENGTH_LONG)
val toast = Toast.<warning descr="Toast created but not shown: did you forget to call `show()` ?">makeText</warning>(context, R.string.app_name, <warning descr="Expected duration `Toast.LENGTH_SHORT` or `Toast.LENGTH_LONG`, a custom duration value is not supported">5000</warning>)
toast.duration
}
init {
Toast.<warning descr="Toast created but not shown: did you forget to call `show()` ?"><warning descr="Toast created but not shown: did you forget to call `show()` ?">makeText(context, "foo", Toast.LENGTH_LONG)</warning></warning>
Toast.<warning descr="Toast created but not shown: did you forget to call `show()` ?">makeText</warning>(context, "foo", Toast.LENGTH_LONG)
}
@android.annotation.SuppressLint("ShowToast")
@@ -61,7 +61,7 @@ class ToastTest(context: Context) : Activity() {
private fun checkSuppress2(context: Context) {
@android.annotation.SuppressLint("ShowToast")
val toast = Toast.makeText(this, "MyToast", Toast.LENGTH_LONG)
val toast = Toast.<warning descr="Toast created but not shown: did you forget to call `show()` ?">makeText</warning>(this, "MyToast", Toast.LENGTH_LONG)
}
class R {
+5 -5
View File
@@ -13,13 +13,13 @@ class WrongAnnotation2 {
companion object {
@SuppressLint("NewApi") // Valid: class-file check on method
fun foobar(view: View, <error descr="The `@SuppressLint` annotation cannot be used on a local variable with the lint check 'NewApi': move out to the surrounding method">@SuppressLint("NewApi")</error> foo: Int) {
fun foobar(view: View, @SuppressLint("NewApi") foo: Int) {
// Invalid: class-file check
<error descr="The `@SuppressLint` annotation cannot be used on a local variable with the lint check 'NewApi': move out to the surrounding method">@SuppressLint("NewApi")</error> // Invalid
@SuppressLint("NewApi") // Invalid
val a: Boolean
<error descr="The `@SuppressLint` annotation cannot be used on a local variable with the lint check 'NewApi': move out to the surrounding method">@SuppressLint("SdCardPath", "NewApi")</error> // Invalid: class-file based check on local variable
@SuppressLint("SdCardPath", "NewApi") // Invalid: class-file based check on local variable
val b: Boolean
<error descr="The `@SuppressLint` annotation cannot be used on a local variable with the lint check 'NewApi': move out to the surrounding method">@android.annotation.SuppressLint("SdCardPath", "NewApi")</error> // Invalid (FQN)
@android.annotation.SuppressLint("SdCardPath", "NewApi") // Invalid (FQN)
val c: Boolean
@SuppressLint("SdCardPath") // Valid: AST-based check
val d: Boolean
@@ -27,7 +27,7 @@ class WrongAnnotation2 {
init {
// Local variable outside method: invalid
<error descr="The `@SuppressLint` annotation cannot be used on a local variable with the lint check 'NewApi': move out to the surrounding method"><error descr="The `@SuppressLint` annotation cannot be used on a local variable with the lint check 'NewApi': move out to the surrounding method">@SuppressLint("NewApi")</error></error>
@SuppressLint("NewApi")
val localvar = 5
}
+1
View File
@@ -22,5 +22,6 @@
<orderEntry type="module" module-name="android-extensions-idea" scope="TEST" />
<orderEntry type="module" module-name="light-classes" />
<orderEntry type="module" module-name="util.runtime" />
<orderEntry type="module" module-name="lint-idea" scope="TEST" />
</component>
</module>