Merge "Add custom Error Prone check for SDK comparisons." into rvc-dev
This commit is contained in:
25
errorprone/Android.bp
Normal file
25
errorprone/Android.bp
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
java_plugin {
|
||||
name: "error_prone_android_framework",
|
||||
|
||||
static_libs: [
|
||||
"error_prone_android_framework_lib",
|
||||
],
|
||||
}
|
||||
|
||||
java_library_host {
|
||||
name: "error_prone_android_framework_lib",
|
||||
|
||||
srcs: ["java/**/*.java"],
|
||||
|
||||
static_libs: [
|
||||
"//external/error_prone:error_prone_core",
|
||||
"//external/dagger2:dagger2-auto-service",
|
||||
],
|
||||
|
||||
plugins: [
|
||||
"//external/dagger2:dagger2-auto-service",
|
||||
],
|
||||
|
||||
javacflags: ["-verbose"],
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.errorprone.bugpatterns.android;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
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.kindIs;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.BinaryTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.FieldMatchers;
|
||||
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;
|
||||
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "AndroidFrameworkTargetSdk",
|
||||
summary = "Verifies that all target SDK comparisons are sane",
|
||||
severity = WARNING)
|
||||
public final class TargetSdkChecker extends BugChecker implements BinaryTreeMatcher {
|
||||
private static final Matcher<ExpressionTree> VERSION_CODE = FieldMatchers
|
||||
.anyFieldInClass("android.os.Build.VERSION_CODES");
|
||||
|
||||
private static final Matcher<BinaryTree> INVALID_OLD_BEHAVIOR = anyOf(
|
||||
allOf(kindIs(Kind.LESS_THAN_EQUAL), binaryTreeExact(anything(), VERSION_CODE)),
|
||||
allOf(kindIs(Kind.GREATER_THAN_EQUAL), binaryTreeExact(VERSION_CODE, anything())));
|
||||
|
||||
private static final Matcher<BinaryTree> INVALID_NEW_BEHAVIOR = anyOf(
|
||||
allOf(kindIs(Kind.GREATER_THAN), binaryTreeExact(anything(), VERSION_CODE)),
|
||||
allOf(kindIs(Kind.LESS_THAN), binaryTreeExact(VERSION_CODE, anything())));
|
||||
|
||||
@Override
|
||||
public Description matchBinary(BinaryTree tree, VisitorState state) {
|
||||
if (INVALID_OLD_BEHAVIOR.matches(tree, state)) {
|
||||
return buildDescription(tree)
|
||||
.setMessage("Legacy behaviors must be written in style "
|
||||
+ "'targetSdk < Build.VERSION_CODES.Z'")
|
||||
.build();
|
||||
}
|
||||
if (INVALID_NEW_BEHAVIOR.matches(tree, state)) {
|
||||
return buildDescription(tree)
|
||||
.setMessage("Modern behaviors must be written in style "
|
||||
+ "'targetSdk >= Build.VERSION_CODES.Z'")
|
||||
.build();
|
||||
}
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
private static Matcher<BinaryTree> binaryTreeExact(Matcher<ExpressionTree> left,
|
||||
Matcher<ExpressionTree> right) {
|
||||
return new Matcher<BinaryTree>() {
|
||||
@Override
|
||||
public boolean matches(BinaryTree tree, VisitorState state) {
|
||||
return left.matches(tree.getLeftOperand(), state)
|
||||
&& right.matches(tree.getRightOperand(), state);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2018 The Error Prone Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.errorprone.matchers;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.ImportTree;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
// TODO(glorioso): this likely wants to be a fluent interface like MethodMatchers.
|
||||
// Ex: [staticField()|instanceField()]
|
||||
// .[onClass(String)|onAnyClass|onClassMatching]
|
||||
// .[named(String)|withAnyName|withNameMatching]
|
||||
/** Static utility methods for creating {@link Matcher}s for detecting references to fields. */
|
||||
public final class FieldMatchers {
|
||||
private FieldMatchers() {}
|
||||
|
||||
public static Matcher<ExpressionTree> anyFieldInClass(String className) {
|
||||
return new FieldReferenceMatcher() {
|
||||
@Override
|
||||
boolean classIsAppropriate(ClassSymbol classSymbol) {
|
||||
return classSymbol.getQualifiedName().contentEquals(className);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean fieldSymbolIsAppropriate(Symbol symbol) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<ExpressionTree> staticField(String className, String fieldName) {
|
||||
return new FieldReferenceMatcher() {
|
||||
@Override
|
||||
boolean classIsAppropriate(ClassSymbol classSymbol) {
|
||||
return classSymbol.getQualifiedName().contentEquals(className);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean fieldSymbolIsAppropriate(Symbol symbol) {
|
||||
return symbol.isStatic() && symbol.getSimpleName().contentEquals(fieldName);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<ExpressionTree> instanceField(String className, String fieldName) {
|
||||
return new FieldReferenceMatcher() {
|
||||
@Override
|
||||
boolean classIsAppropriate(ClassSymbol classSymbol) {
|
||||
return classSymbol.getQualifiedName().contentEquals(className);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean fieldSymbolIsAppropriate(Symbol symbol) {
|
||||
return !symbol.isStatic() && symbol.getSimpleName().contentEquals(fieldName);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private abstract static class FieldReferenceMatcher implements Matcher<ExpressionTree> {
|
||||
@Override
|
||||
public boolean matches(ExpressionTree expressionTree, VisitorState state) {
|
||||
return isSymbolFieldInAppropriateClass(ASTHelpers.getSymbol(expressionTree))
|
||||
// Don't match if this is part of a static import tree, since they will get the finding
|
||||
// on any usage of the field in their source.
|
||||
&& ASTHelpers.findEnclosingNode(state.getPath(), ImportTree.class) == null;
|
||||
}
|
||||
|
||||
private boolean isSymbolFieldInAppropriateClass(@Nullable Symbol symbol) {
|
||||
if (symbol == null) {
|
||||
return false;
|
||||
}
|
||||
return symbol.getKind().isField()
|
||||
&& fieldSymbolIsAppropriate(symbol)
|
||||
&& classIsAppropriate(symbol.owner.enclClass());
|
||||
}
|
||||
|
||||
abstract boolean fieldSymbolIsAppropriate(Symbol symbol);
|
||||
|
||||
abstract boolean classIsAppropriate(ClassSymbol classSymbol);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,10 @@
|
||||
java_defaults {
|
||||
name: "services_defaults",
|
||||
plugins: [
|
||||
"error_prone_android_framework",
|
||||
],
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "services-main-sources",
|
||||
srcs: ["java/**/*.java"],
|
||||
@@ -83,7 +90,6 @@ java_library {
|
||||
|
||||
// Uncomment to enable output of certain warnings (deprecated, unchecked)
|
||||
//javacflags: ["-Xlint"],
|
||||
|
||||
}
|
||||
|
||||
// native library
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.accessibility",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.accessibility-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.appprediction",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.appprediction-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.appwidget",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.appwidget-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.autofill",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.autofill-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.backup",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.backup-sources"],
|
||||
libs: ["services.core"],
|
||||
static_libs: ["backuplib"],
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.companion",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.companion-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.contentcapture",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.contentcapture-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.contentsuggestions",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.contentsuggestions-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -148,6 +148,7 @@ java_genrule {
|
||||
|
||||
java_library {
|
||||
name: "services.core",
|
||||
defaults: ["services_defaults"],
|
||||
static_libs: ["services.core.priorityboosted"],
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.coverage",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.coverage-sources"],
|
||||
libs: ["jacocoagent"],
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.devicepolicy",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.devicepolicy-sources"],
|
||||
|
||||
libs: [
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.midi",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.midi-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.net",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [
|
||||
":net-module-utils-srcs",
|
||||
":services.net-sources",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
java_library_static {
|
||||
name: "services.people",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: ["java/**/*.java"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.print",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.print-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.restrictions",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.restrictions-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
java_library_static {
|
||||
name: "services.startop",
|
||||
defaults: ["services_defaults"],
|
||||
|
||||
static_libs: [
|
||||
// frameworks/base/startop/iorap
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.systemcaptions",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.systemcaptions-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.usage",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.usage-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.usb",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.usb-sources"],
|
||||
|
||||
libs: [
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.voiceinteraction",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [":services.voiceinteraction-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ filegroup {
|
||||
|
||||
java_library_static {
|
||||
name: "services.wifi",
|
||||
defaults: ["services_defaults"],
|
||||
srcs: [
|
||||
":services.wifi-sources",
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user