diff --git a/Android.bp b/Android.bp index 5af77562de85..f69f9d856d5e 100644 --- a/Android.bp +++ b/Android.bp @@ -598,6 +598,11 @@ java_library { "//frameworks/base/apex/jobscheduler/framework", "//frameworks/base/packages/Tethering/tests/unit", ], + errorprone: { + javacflags: [ + "-Xep:AndroidFrameworkCompatChange:ERROR", + ], + }, } // This "framework" module is NOT installed to the device. It's diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java index 8829b0d3c649..9c84f50b76bb 100644 --- a/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java +++ b/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java @@ -17,12 +17,13 @@ package com.google.errorprone.bugpatterns.android; import static com.google.errorprone.BugPattern.SeverityLevel.WARNING; +import static com.google.errorprone.bugpatterns.android.TargetSdkChecker.binaryTreeExact; import static com.google.errorprone.matchers.FieldMatchers.anyFieldInClass; import static com.google.errorprone.matchers.FieldMatchers.staticField; import static com.google.errorprone.matchers.Matchers.allOf; import static com.google.errorprone.matchers.Matchers.anyOf; import static com.google.errorprone.matchers.Matchers.anything; -import static com.google.errorprone.matchers.Matchers.binaryTree; +import static com.google.errorprone.matchers.Matchers.kindIs; import static com.google.errorprone.matchers.Matchers.not; import com.google.auto.service.AutoService; @@ -34,6 +35,7 @@ import com.google.errorprone.matchers.Description; import com.google.errorprone.matchers.Matcher; import com.sun.source.tree.BinaryTree; import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.Tree.Kind; /** * Each SDK level often has dozens of different behavior changes, which can be @@ -85,14 +87,28 @@ public final class CompatChangeChecker extends BugChecker implements BinaryTreeM staticField("android.os.Build.VERSION_CODES", "O"), staticField("android.os.Build.VERSION_CODES", "O_MR1"), staticField("android.os.Build.VERSION_CODES", "P"), - staticField("android.os.Build.VERSION_CODES", "Q")); + staticField("android.os.Build.VERSION_CODES", "Q"), + staticField("android.os.Build.VERSION_CODES", "R")); + + private static final Matcher R_VERSION_CODE = + staticField("android.os.Build.VERSION_CODES", "R"); + + private static final Matcher CUR_DEVELOPMENT_VERSION_CODE = + staticField("android.os.Build.VERSION_CODES", "CUR_DEVELOPMENT"); private static final Matcher MODERN_VERSION_CODE = - allOf(VERSION_CODE, not(LEGACY_VERSION_CODE)); + allOf(VERSION_CODE, not(LEGACY_VERSION_CODE), not(CUR_DEVELOPMENT_VERSION_CODE)); + + private static final Matcher BOOLEAN_OPERATOR = anyOf( + kindIs(Kind.LESS_THAN), kindIs(Kind.LESS_THAN_EQUAL), + kindIs(Kind.GREATER_THAN), kindIs(Kind.GREATER_THAN_EQUAL), + kindIs(Kind.EQUAL_TO), kindIs(Kind.NOT_EQUAL_TO)); private static final Matcher INVALID = anyOf( - binaryTree(MODERN_VERSION_CODE, anything()), - binaryTree(anything(), MODERN_VERSION_CODE)); + allOf(BOOLEAN_OPERATOR, binaryTreeExact(MODERN_VERSION_CODE, anything())), + allOf(BOOLEAN_OPERATOR, binaryTreeExact(anything(), MODERN_VERSION_CODE)), + allOf(kindIs(Kind.GREATER_THAN), binaryTreeExact(anything(), R_VERSION_CODE)), + allOf(kindIs(Kind.LESS_THAN), binaryTreeExact(R_VERSION_CODE, anything()))); @Override public Description matchBinary(BinaryTree tree, VisitorState state) { diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java index 232cf3f0d677..e1ebf42fec19 100644 --- a/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java +++ b/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java @@ -89,7 +89,7 @@ public final class TargetSdkChecker extends BugChecker implements BinaryTreeMatc return Description.NO_MATCH; } - private static Matcher binaryTreeExact(Matcher left, + static Matcher binaryTreeExact(Matcher left, Matcher right) { return new Matcher() { @Override diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/CompatChangeCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/CompatChangeCheckerTest.java index 105633e4de28..4625d43a1648 100644 --- a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/CompatChangeCheckerTest.java +++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/CompatChangeCheckerTest.java @@ -42,17 +42,17 @@ public class CompatChangeCheckerTest { "public class Example {", " void test(int targetSdkVersion) {", " // BUG: Diagnostic contains:", - " if (targetSdkVersion < Build.VERSION_CODES.R) { }", + " if (targetSdkVersion < Build.VERSION_CODES.S) { }", " // BUG: Diagnostic contains:", - " if (targetSdkVersion <= Build.VERSION_CODES.R) { }", + " if (targetSdkVersion <= Build.VERSION_CODES.S) { }", " // BUG: Diagnostic contains:", - " if (targetSdkVersion > Build.VERSION_CODES.R) { }", + " if (targetSdkVersion > Build.VERSION_CODES.S) { }", " // BUG: Diagnostic contains:", - " if (targetSdkVersion >= Build.VERSION_CODES.R) { }", + " if (targetSdkVersion >= Build.VERSION_CODES.S) { }", " // BUG: Diagnostic contains:", - " if (targetSdkVersion == Build.VERSION_CODES.R) { }", + " if (targetSdkVersion == Build.VERSION_CODES.S) { }", " // BUG: Diagnostic contains:", - " if (targetSdkVersion != Build.VERSION_CODES.R) { }", + " if (targetSdkVersion != Build.VERSION_CODES.S) { }", " }", "}") .doTest(); @@ -63,18 +63,29 @@ public class CompatChangeCheckerTest { compilationHelper .addSourceFile("/android/os/Build.java") .addSourceLines("Example.java", - "import static android.os.Build.VERSION_CODES.R;", + "import android.os.Build;", + "import static android.os.Build.VERSION_CODES.S;", "public class Example {", " void test(int targetSdkVersion) {", " // BUG: Diagnostic contains:", - " boolean indirect = R > targetSdkVersion;", + " boolean indirect = S >= targetSdkVersion;", + " // BUG: Diagnostic contains:", + " if (targetSdkVersion > Build.VERSION_CODES.R) { }", + " if (targetSdkVersion >= Build.VERSION_CODES.R) { }", + " if (targetSdkVersion < Build.VERSION_CODES.R) { }", + " if (targetSdkVersion <= Build.VERSION_CODES.R) { }", + " // BUG: Diagnostic contains:", + " if (Build.VERSION_CODES.R < targetSdkVersion) { }", + " if (Build.VERSION_CODES.R <= targetSdkVersion) { }", + " if (Build.VERSION_CODES.R > targetSdkVersion) { }", + " if (Build.VERSION_CODES.R >= targetSdkVersion) { }", " }", "}") .doTest(); } @Test - public void testLegacyIgnored() { + public void testIgnored() { compilationHelper .addSourceFile("/android/os/Build.java") .addSourceLines("Example.java", @@ -82,6 +93,8 @@ public class CompatChangeCheckerTest { "public class Example {", " void test(int targetSdkVersion) {", " if (targetSdkVersion < Build.VERSION_CODES.DONUT) { }", + " String result = \"test\" + Build.VERSION_CODES.S;", + " if (targetSdkVersion != Build.VERSION_CODES.CUR_DEVELOPMENT) { }", " }", "}") .doTest(); diff --git a/errorprone/tests/res/android/os/Build.java b/errorprone/tests/res/android/os/Build.java index 0b51bdba0731..2d354e2ac370 100644 --- a/errorprone/tests/res/android/os/Build.java +++ b/errorprone/tests/res/android/os/Build.java @@ -18,7 +18,9 @@ package android.os; public class Build { public static class VERSION_CODES { + public static final int CUR_DEVELOPMENT = 10000; public static final int DONUT = 4; public static final int R = 30; + public static final int S = CUR_DEVELOPMENT; } } diff --git a/services/Android.bp b/services/Android.bp index ef52c2aff002..971f4dda440c 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -3,6 +3,11 @@ java_defaults { plugins: [ "error_prone_android_framework", ], + errorprone: { + javacflags: [ + "-Xep:AndroidFrameworkCompatChange:ERROR", + ], + }, } filegroup {