Support lint suppression

Fix reported scope of SysUI's linters so that @SuppressWarnings
annotation can be used when necessary.

Test: SystemUILintCheckerTest
Bug: 238457012
Bug: 258902612
Change-Id: Ie6650ae1a33e5401ab6ceb521b3d02be93641477
This commit is contained in:
Peter Kalauskas
2022-11-16 11:54:29 -08:00
parent 82e7167b9c
commit 262448f65b
16 changed files with 255 additions and 44 deletions

View File

@@ -59,11 +59,11 @@ class BindServiceOnMainThreadDetector : Detector(), SourceCodeScanner {
!hasWorkerThreadAnnotation(context, node.getParentOfType(UClass::class.java))
) {
context.report(
ISSUE,
method,
context.getLocation(node),
"This method should be annotated with `@WorkerThread` because " +
"it calls ${method.name}",
issue = ISSUE,
location = context.getLocation(node),
message =
"This method should be annotated with `@WorkerThread` because " +
"it calls ${method.name}",
)
}
}

View File

@@ -52,10 +52,9 @@ class BroadcastSentViaContextDetector : Detector(), SourceCodeScanner {
val evaluator = context.evaluator
if (evaluator.isMemberInSubClassOf(method, CLASS_CONTEXT)) {
context.report(
ISSUE,
method,
context.getNameLocation(node),
"`Context.${method.name}()` should be replaced with " +
issue = ISSUE,
location = context.getNameLocation(node),
message = "`Context.${method.name}()` should be replaced with " +
"`BroadcastSender.${method.name}()`"
)
}

View File

@@ -38,10 +38,9 @@ class NonInjectedMainThreadDetector : Detector(), SourceCodeScanner {
override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
if (context.evaluator.isMemberInSubClassOf(method, CLASS_CONTEXT)) {
context.report(
ISSUE,
method,
context.getNameLocation(node),
"Replace with injected `@Main Executor`."
issue = ISSUE,
location = context.getNameLocation(node),
message = "Replace with injected `@Main Executor`."
)
}
}

View File

@@ -44,11 +44,11 @@ class NonInjectedServiceDetector : Detector(), SourceCodeScanner {
method.containingClass?.qualifiedName == CLASS_CONTEXT
) {
context.report(
ISSUE,
method,
context.getNameLocation(node),
"Use `@Inject` to get system-level service handles instead of " +
"`Context.getSystemService()`"
issue = ISSUE,
location = context.getNameLocation(node),
message =
"Use `@Inject` to get system-level service handles instead of " +
"`Context.getSystemService()`"
)
} else if (
evaluator.isStatic(method) &&
@@ -56,10 +56,10 @@ class NonInjectedServiceDetector : Detector(), SourceCodeScanner {
method.containingClass?.qualifiedName == "android.accounts.AccountManager"
) {
context.report(
ISSUE,
method,
context.getNameLocation(node),
"Replace `AccountManager.get()` with an injected instance of `AccountManager`"
issue = ISSUE,
location = context.getNameLocation(node),
message =
"Replace `AccountManager.get()` with an injected instance of `AccountManager`"
)
}
}

View File

@@ -38,10 +38,10 @@ class RegisterReceiverViaContextDetector : Detector(), SourceCodeScanner {
override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
if (context.evaluator.isMemberInSubClassOf(method, CLASS_CONTEXT)) {
context.report(
ISSUE,
method,
context.getNameLocation(node),
"Register `BroadcastReceiver` using `BroadcastDispatcher` instead of `Context`"
issue = ISSUE,
location = context.getNameLocation(node),
message = "Register `BroadcastReceiver` using `BroadcastDispatcher` instead " +
"of `Context`"
)
}
}

View File

@@ -46,10 +46,10 @@ class SlowUserQueryDetector : Detector(), SourceCodeScanner {
method.containingClass?.qualifiedName == "android.app.ActivityManager"
) {
context.report(
ISSUE_SLOW_USER_ID_QUERY,
method,
context.getNameLocation(node),
"Use `UserTracker.getUserId()` instead of `ActivityManager.getCurrentUser()`"
issue = ISSUE_SLOW_USER_ID_QUERY,
location = context.getNameLocation(node),
message =
"Use `UserTracker.getUserId()` instead of `ActivityManager.getCurrentUser()`"
)
}
if (
@@ -58,10 +58,9 @@ class SlowUserQueryDetector : Detector(), SourceCodeScanner {
method.containingClass?.qualifiedName == "android.os.UserManager"
) {
context.report(
ISSUE_SLOW_USER_INFO_QUERY,
method,
context.getNameLocation(node),
"Use `UserTracker.getUserInfo()` instead of `UserManager.getUserInfo()`"
issue = ISSUE_SLOW_USER_INFO_QUERY,
location = context.getNameLocation(node),
message = "Use `UserTracker.getUserInfo()` instead of `UserManager.getUserInfo()`"
)
}
}

View File

@@ -44,10 +44,9 @@ class SoftwareBitmapDetector : Detector(), SourceCodeScanner {
val evaluator = context.evaluator
if (evaluator.isMemberInClass(referenced as? PsiField, "android.graphics.Bitmap.Config")) {
context.report(
ISSUE,
referenced,
context.getNameLocation(reference),
"Replace software bitmap with `Config.HARDWARE`"
issue = ISSUE,
location = context.getNameLocation(reference),
message = "Replace software bitmap with `Config.HARDWARE`"
)
}
}

View File

@@ -66,10 +66,9 @@ class StaticSettingsProviderDetector : Detector(), SourceCodeScanner {
val subclassName = className.substring(CLASS_SETTINGS.length + 1)
context.report(
ISSUE,
method,
context.getNameLocation(node),
"`@Inject` a ${subclassName}Settings instead"
issue = ISSUE,
location = context.getNameLocation(node),
message = "`@Inject` a ${subclassName}Settings instead"
)
}

View File

@@ -125,6 +125,32 @@ class BindServiceOnMainThreadDetectorTest : SystemUILintDetectorTest() {
)
}
@Test
fun testSuppressUnbindService() {
lint()
.files(
TestFiles.java(
"""
package test.pkg;
import android.content.Context;
import android.content.ServiceConnection;
@SuppressLint("BindServiceOnMainThread")
public class TestClass {
public void unbind(Context context, ServiceConnection connection) {
context.unbindService(connection);
}
}
"""
)
.indented(),
*stubs
)
.issues(BindServiceOnMainThreadDetector.ISSUE)
.run()
.expectClean()
}
@Test
fun testWorkerMethod() {
lint()

View File

@@ -128,6 +128,34 @@ class BroadcastSentViaContextDetectorTest : SystemUILintDetectorTest() {
)
}
@Test
fun testSuppressSendBroadcastInActivity() {
lint()
.files(
TestFiles.java(
"""
package test.pkg;
import android.app.Activity;
import android.os.UserHandle;
public class TestClass {
@SuppressWarnings("BroadcastSentViaContext")
public void send(Activity activity) {
Intent intent = new Intent(Intent.ACTION_VIEW);
activity.sendBroadcastAsUser(intent, UserHandle.ALL, "permission");
}
}
"""
)
.indented(),
*stubs
)
.issues(BroadcastSentViaContextDetector.ISSUE)
.run()
.expectClean()
}
@Test
fun testSendBroadcastInBroadcastSender() {
lint()

View File

@@ -60,6 +60,32 @@ class NonInjectedMainThreadDetectorTest : SystemUILintDetectorTest() {
)
}
@Test
fun testSuppressGetMainThreadHandler() {
lint()
.files(
TestFiles.java(
"""
package test.pkg;
import android.content.Context;
import android.os.Handler;
@SuppressWarnings("NonInjectedMainThread")
public class TestClass {
public void test(Context context) {
Handler mainThreadHandler = context.getMainThreadHandler();
}
}
"""
)
.indented(),
*stubs
)
.issues(NonInjectedMainThreadDetector.ISSUE)
.run()
.expectClean()
}
@Test
fun testGetMainLooper() {
lint()

View File

@@ -90,6 +90,32 @@ class NonInjectedServiceDetectorTest : SystemUILintDetectorTest() {
)
}
@Test
fun testSuppressGetServiceWithClass() {
lint()
.files(
TestFiles.java(
"""
package test.pkg;
import android.content.Context;
import android.os.UserManager;
public class TestClass {
@SuppressLint("NonInjectedService")
public void getSystemServiceWithoutDagger(Context context) {
context.getSystemService(UserManager.class);
}
}
"""
)
.indented(),
*stubs
)
.issues(NonInjectedServiceDetector.ISSUE)
.run()
.expectClean()
}
@Test
fun testGetAccountManager() {
lint()

View File

@@ -62,6 +62,34 @@ class RegisterReceiverViaContextDetectorTest : SystemUILintDetectorTest() {
)
}
@Test
fun testSuppressRegisterReceiver() {
lint()
.files(
TestFiles.java(
"""
package test.pkg;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
@SuppressWarnings("RegisterReceiverViaContext")
public class TestClass {
public void bind(Context context, BroadcastReceiver receiver,
IntentFilter filter) {
context.registerReceiver(receiver, filter, 0);
}
}
"""
)
.indented(),
*stubs
)
.issues(RegisterReceiverViaContextDetector.ISSUE)
.run()
.expectClean()
}
@Test
fun testRegisterReceiverAsUser() {
lint()

View File

@@ -76,7 +76,7 @@ class SlowUserQueryDetectorTest : SystemUILintDetectorTest() {
import android.os.UserManager;
public class TestClass {
public void slewlyGetUserInfo(UserManager userManager) {
public void slowlyGetUserInfo(UserManager userManager) {
userManager.getUserInfo();
}
}
@@ -100,6 +100,34 @@ class SlowUserQueryDetectorTest : SystemUILintDetectorTest() {
)
}
@Test
fun testSuppressGetUserInfo() {
lint()
.files(
TestFiles.java(
"""
package test.pkg;
import android.os.UserManager;
public class TestClass {
@SuppressWarnings("SlowUserInfoQuery")
public void slowlyGetUserInfo(UserManager userManager) {
userManager.getUserInfo();
}
}
"""
)
.indented(),
*stubs
)
.issues(
SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
)
.run()
.expectClean()
}
@Test
fun testUserTrackerGetUserId() {
lint()

View File

@@ -62,6 +62,31 @@ class SoftwareBitmapDetectorTest : SystemUILintDetectorTest() {
)
}
@Test
fun testSuppressSoftwareBitmap() {
lint()
.files(
TestFiles.java(
"""
import android.graphics.Bitmap;
@SuppressWarnings("SoftwareBitmap")
public class TestClass {
public void test() {
Bitmap.createBitmap(300, 300, Bitmap.Config.RGB_565);
Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
}
}
"""
)
.indented(),
*stubs
)
.issues(SoftwareBitmapDetector.ISSUE)
.run()
.expectClean()
}
@Test
fun testHardwareBitmap() {
lint()

View File

@@ -28,7 +28,7 @@ class StaticSettingsProviderDetectorTest : SystemUILintDetectorTest() {
override fun getIssues(): List<Issue> = listOf(StaticSettingsProviderDetector.ISSUE)
@Test
fun testGetServiceWithString() {
fun testSuppressGetServiceWithString() {
lint()
.files(
TestFiles.java(
@@ -204,5 +204,34 @@ class StaticSettingsProviderDetectorTest : SystemUILintDetectorTest() {
)
}
@Test
fun testGetServiceWithString() {
lint()
.files(
TestFiles.java(
"""
package test.pkg;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
public class TestClass {
@SuppressWarnings("StaticSettingsProvider")
public void getSystemServiceWithoutDagger(Context context) {
final ContentResolver cr = mContext.getContentResolver();
Global.getFloat(cr, Settings.Global.UNLOCK_SOUND);
}
}
"""
)
.indented(),
*stubs
)
.issues(StaticSettingsProviderDetector.ISSUE)
.run()
.expectClean()
}
private val stubs = androidStubs
}