Merge "Add custom Error Prone check for SDK comparisons." into rvc-dev

This commit is contained in:
Jeff Sharkey
2020-05-04 23:10:06 +00:00
committed by Android (Google) Code Review
26 changed files with 234 additions and 1 deletions

25
errorprone/Android.bp Normal file
View 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"],
}

View File

@@ -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);
}
};
}
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.accessibility",
defaults: ["services_defaults"],
srcs: [":services.accessibility-sources"],
libs: ["services.core"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.appprediction",
defaults: ["services_defaults"],
srcs: [":services.appprediction-sources"],
libs: ["services.core"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.appwidget",
defaults: ["services_defaults"],
srcs: [":services.appwidget-sources"],
libs: ["services.core"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.autofill",
defaults: ["services_defaults"],
srcs: [":services.autofill-sources"],
libs: ["services.core"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.backup",
defaults: ["services_defaults"],
srcs: [":services.backup-sources"],
libs: ["services.core"],
static_libs: ["backuplib"],

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.companion",
defaults: ["services_defaults"],
srcs: [":services.companion-sources"],
libs: ["services.core"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.contentcapture",
defaults: ["services_defaults"],
srcs: [":services.contentcapture-sources"],
libs: ["services.core"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.contentsuggestions",
defaults: ["services_defaults"],
srcs: [":services.contentsuggestions-sources"],
libs: ["services.core"],
}

View File

@@ -148,6 +148,7 @@ java_genrule {
java_library {
name: "services.core",
defaults: ["services_defaults"],
static_libs: ["services.core.priorityboosted"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.coverage",
defaults: ["services_defaults"],
srcs: [":services.coverage-sources"],
libs: ["jacocoagent"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.devicepolicy",
defaults: ["services_defaults"],
srcs: [":services.devicepolicy-sources"],
libs: [

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.midi",
defaults: ["services_defaults"],
srcs: [":services.midi-sources"],
libs: ["services.core"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.net",
defaults: ["services_defaults"],
srcs: [
":net-module-utils-srcs",
":services.net-sources",

View File

@@ -1,5 +1,6 @@
java_library_static {
name: "services.people",
defaults: ["services_defaults"],
srcs: ["java/**/*.java"],
libs: ["services.core"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.print",
defaults: ["services_defaults"],
srcs: [":services.print-sources"],
libs: ["services.core"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.restrictions",
defaults: ["services_defaults"],
srcs: [":services.restrictions-sources"],
libs: ["services.core"],
}

View File

@@ -16,6 +16,7 @@
java_library_static {
name: "services.startop",
defaults: ["services_defaults"],
static_libs: [
// frameworks/base/startop/iorap

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.systemcaptions",
defaults: ["services_defaults"],
srcs: [":services.systemcaptions-sources"],
libs: ["services.core"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.usage",
defaults: ["services_defaults"],
srcs: [":services.usage-sources"],
libs: ["services.core"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.usb",
defaults: ["services_defaults"],
srcs: [":services.usb-sources"],
libs: [

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.voiceinteraction",
defaults: ["services_defaults"],
srcs: [":services.voiceinteraction-sources"],
libs: ["services.core"],
}

View File

@@ -7,6 +7,7 @@ filegroup {
java_library_static {
name: "services.wifi",
defaults: ["services_defaults"],
srcs: [
":services.wifi-sources",
],