forked from SukeeratSG/Octavi_base
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add custom Error Prone check for SDK comparisons.
Over the years we've had several obscure bugs related to how SDK level comparisons are performed, specifically during the window of time where we've started distributing the "frankenbuild" to developers. Consider the case where a framework developer shipping release "R" wants to only grant a specific behavior to modern apps; they could write this in two different ways: 1. if (targetSdkVersion > Build.VERSION_CODES.Q) { 2. if (targetSdkVersion >= Build.VERSION_CODES.R) { The safer of these two options is (2), which will ensure that developers only get the behavior when *both* the app and the platform concur on the specific SDK level having shipped. Consider the breakage that would happen with option (1) if we started shipping APKs that are based on the final R SDK, but are then installed on earlier preview releases which still consider R to be CUR_DEVELOPMENT; they'd risk crashing due to behaviors that were never part of the official R SDK. Bug: 64412239 Test: ./build/soong/soong_ui.bash --make-mode services RUN_ERROR_PRONE=true Exempt-From-Owner-Approval: trivial blueprint changes Change-Id: Ia20181f8602451ac9a719ea488d148e160708592
- Loading branch information
Showing
26 changed files
with
234 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"], | ||
} |
81 changes: 81 additions & 0 deletions
81
errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
}; | ||
} | ||
} |
99 changes: 99 additions & 0 deletions
99
errorprone/java/com/google/errorprone/matchers/FieldMatchers.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
java_library_static { | ||
name: "services.people", | ||
defaults: ["services_defaults"], | ||
srcs: ["java/**/*.java"], | ||
libs: ["services.core"], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.