Error prone check added to check unbinded subscriptions#156
Error prone check added to check unbinded subscriptions#156ZacSweers merged 26 commits intouber:masterfrom
Conversation
|
Will start review once the to-dos are finished, unless you wanted me to give early feedback now before. Let me know |
|
Yeah. It will be great if you can give some early feedback. Most of the remaining changes will only be in |
gradle/dependencies.gradle
Outdated
| ] | ||
|
|
||
| def apt = [ | ||
| autoService : "com.google.auto.service:auto-service:1.0-rc3", |
There was a problem hiding this comment.
nit: make this match the rest of this file's style
|
|
||
| checkerFramework: 'org.checkerframework:dataflow:2.3.0', | ||
| errorProneCheckApi: "com.google.errorprone:error_prone_check_api:${versions.errorProne}", | ||
| errorProne: "com.google.errorprone:error_prone_core:${versions.errorProne}", |
There was a problem hiding this comment.
nit: this goes above errorProneCheckApi alphabetically
|
|
||
| // we use this config to get the path of the JDK 9 javac jar, to | ||
| // stick it in the bootclasspath when running tests | ||
| configurations.maybeCreate("epJavac") |
There was a problem hiding this comment.
actually if you wouldn't mind taking a general review of this config, I'd appreciate the extra set of eyes
| @@ -0,0 +1,70 @@ | |||
| plugins { | |||
| id "net.ltgt.errorprone" version "0.0.13" | |||
| id "com.github.johnrengelman.shadow" version "2.0.1" | |||
There was a problem hiding this comment.
can you explain the shadow bits here?
There was a problem hiding this comment.
I am trying to create a fat jar here and the steps are taken from - NullAway's build.gradle - dependency part.
It is not working in any case as I am not able to use it in the sample project. Will be fixing it over the weekend. I am not sure what is the best way to publish an error-prone check.
There was a problem hiding this comment.
You should not need to create a fat jar. the jar with just the classes from this module can be consumed by anyone that uses error prone
There was a problem hiding this comment.
Yeah all the shadow stuff isn't needed here. NullAway needs it due to a forked dependence
| } | ||
|
|
||
| test { | ||
| maxHeapSize = "1024m" |
| */ | ||
| @AutoService(BugChecker.class) | ||
| @BugPattern( | ||
| name = "RxJavaMissingAutoDisposeErrorChecker", |
There was a problem hiding this comment.
I would recommend renaming this to
MissingAutoDisposeErrorChecker
Adding Rxjava at the start seems redundant. Similar to @hzsweers comment earlier about removing rx from the artifact identifier
| private static final ImmutableList<MethodMatchers.MethodNameMatcher> TO_CALL_MATCHERS; | ||
| private static final ImmutableList<MethodMatchers.MethodNameMatcher> SUBSCRIBE_MATCHERS; | ||
| private static final String SUBSCRIBE = "subscribe"; | ||
| private static final String TO = "to"; |
There was a problem hiding this comment.
We don't need to support the to implementation since it's going away
| ImmutableList.Builder<String> builder = new ImmutableList.Builder<>(); | ||
| classesWithLifecycle = builder | ||
| .add("android.app.Activity") | ||
| .add("android.app.Fragment") |
There was a problem hiding this comment.
we should support support fragments out of the box. I'm kind of thinking we shouldn't check any by default though, and leave it totally up to the user. Will think on it more
There was a problem hiding this comment.
It is s already added.
| } | ||
|
|
||
| static { | ||
| ImmutableList.Builder<MethodMatchers.MethodNameMatcher> builder = new ImmutableList.Builder<>(); |
|
|
||
| ImmutableList.Builder<MethodMatchers.MethodNameMatcher> builder2 | ||
| = new ImmutableList.Builder<>(); | ||
| builder2 |
There was a problem hiding this comment.
why not continue the fluent API after creating the builder?
| */ | ||
| @AutoService(BugChecker.class) | ||
| @BugPattern( | ||
| name = "RxJavaMissingAutoDisposeErrorChecker", |
There was a problem hiding this comment.
I would recommend renaming this to
MissingAutoDisposeErrorChecker
Adding Rxjava at the start seems redundant. Similar to @hzsweers comment earlier about removing rx from the artifact identifier
| @BugPattern( | ||
| name = "RxJavaMissingAutoDisposeErrorChecker", | ||
| summary = "Always apply an Autodispose scope before subscribing", | ||
| category = JDK, |
There was a problem hiding this comment.
I would recommend using the concurrency tag instead of the deprecated categories
|
|
||
| @Override | ||
| public String linkUrl() { | ||
| return "https://github.com/uber/RIBs" |
|
|
||
| // we use this config to get the path of the JDK 9 javac jar, to | ||
| // stick it in the bootclasspath when running tests | ||
| configurations.maybeCreate("epJavac") |
There was a problem hiding this comment.
Many config options in this file are not required. They are specific to nullaway and do not translate here.
Remove this line
There was a problem hiding this comment.
This actually might be needed for unit tests, to get EP java in bootclasspath. Can try without first.
There was a problem hiding this comment.
This is needed for unit tests.
|
|
||
| compileOnly deps.build.errorProneCheckApi | ||
|
|
||
| errorprone deps.build.errorProne |
| @@ -0,0 +1,70 @@ | |||
| plugins { | |||
| id "net.ltgt.errorprone" version "0.0.13" | |||
| id "com.github.johnrengelman.shadow" version "2.0.1" | |||
There was a problem hiding this comment.
You should not need to create a fat jar. the jar with just the classes from this module can be consumed by anyone that uses error prone
| @@ -0,0 +1,70 @@ | |||
| plugins { | |||
| id "net.ltgt.errorprone" version "0.0.13" | |||
| @@ -0,0 +1,70 @@ | |||
| plugins { | |||
| id "net.ltgt.errorprone" version "0.0.13" | |||
| id "com.github.johnrengelman.shadow" version "2.0.1" | |||
| } | ||
| testCompile project(':autodispose') | ||
|
|
||
| epJavac deps.build.errorProneCheckApi |
| epJavac deps.build.errorProneCheckApi | ||
| } | ||
|
|
||
| shadowJar { |
There was a problem hiding this comment.
Remove everything from this line and below (Change the maven bits to just match what other projects do)
|
|
||
| @Override | ||
| public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { | ||
| if (matcher(classesWithLifecycle).matches(tree, state)) { |
There was a problem hiding this comment.
The result of matcher(classesWithLifecycle) should be cached in an instance field
| Type.ClassType enclosingClassType = ASTHelpers.getType(enclosingClass); | ||
|
|
||
| for (String s : classesWithLifecycle) { | ||
| Type lifecycleType = state.getTypeFromString(s); |
There was a problem hiding this comment.
Small optimization: store classesWithLifecycle as a List<Type>. The call getTypeFromString() can be a bit costly (though for this checker it may not get called very often)
There was a problem hiding this comment.
Missed it. Will fix in a separate commit.
There was a problem hiding this comment.
@msridhar quick question - do you mean to cache it when we will call it the first time? Can we get the type from a string without visitor state? I am not sure how to do it eagerly.
There was a problem hiding this comment.
Yeah you're right, hard to do eagerly. We can skip this optimization for now I think; this code shouldn't run all that often.
| } | ||
| return false; | ||
| } catch (ClassCastException e) { | ||
| return false; |
There was a problem hiding this comment.
Why catch a ClassCastException here?
| SUBSCRIBE_MATCHERS = builder3.build(); | ||
| } | ||
|
|
||
| private static final Matcher<ExpressionTree> METHOD_NAME_MATCHERS = |
bangarharshit
left a comment
There was a problem hiding this comment.
Addressed comments except caching the types in a list. Will push a commit for that.
gradle/dependencies.gradle
Outdated
| ] | ||
|
|
||
| def apt = [ | ||
| autoService : "com.google.auto.service:auto-service:1.0-rc3", |
|
|
||
| checkerFramework: 'org.checkerframework:dataflow:2.3.0', | ||
| errorProneCheckApi: "com.google.errorprone:error_prone_check_api:${versions.errorProne}", | ||
| errorProne: "com.google.errorprone:error_prone_core:${versions.errorProne}", |
| @@ -0,0 +1,70 @@ | |||
| plugins { | |||
| id "net.ltgt.errorprone" version "0.0.13" | |||
| @@ -0,0 +1,70 @@ | |||
| plugins { | |||
| id "net.ltgt.errorprone" version "0.0.13" | |||
| id "com.github.johnrengelman.shadow" version "2.0.1" | |||
| @@ -0,0 +1,70 @@ | |||
| plugins { | |||
| id "net.ltgt.errorprone" version "0.0.13" | |||
| id "com.github.johnrengelman.shadow" version "2.0.1" | |||
| Type.ClassType enclosingClassType = ASTHelpers.getType(enclosingClass); | ||
|
|
||
| for (String s : classesWithLifecycle) { | ||
| Type lifecycleType = state.getTypeFromString(s); |
There was a problem hiding this comment.
Missed it. Will fix in a separate commit.
|
|
||
| @Override | ||
| public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { | ||
| if (matcher(classesWithLifecycle).matches(tree, state)) { |
| SUBSCRIBE_MATCHERS = builder3.build(); | ||
| } | ||
|
|
||
| private static final Matcher<ExpressionTree> METHOD_NAME_MATCHERS = |
| @BugPattern( | ||
| name = "RxJavaMissingAutoDisposeErrorChecker", | ||
| summary = "Always apply an Autodispose scope before subscribing", | ||
| category = JDK, |
|
|
||
| @Override | ||
| public String linkUrl() { | ||
| return "https://github.com/uber/RIBs" |
| @@ -0,0 +1,32 @@ | |||
| plugins { | |||
| id "net.ltgt.errorprone" version "0.0.13" | |||
| id "java" | |||
There was a problem hiding this comment.
java-library, then use api and implementation configurations in dependencies
|
|
||
| public MissingAutoDisposeErrorChecker(ErrorProneFlags flags) { | ||
| Optional<ImmutableList<String>> inputClasses = flags.getList("AutoDisposeLeakCheck"); | ||
| ImmutableList<String> classesWithLifecycle = new ImmutableList.Builder<String>() |
There was a problem hiding this comment.
This list seems to still be missing support fragments, LifecycleOwner, and ScopeProvider. Is that intentional? Also, we should have a way to allow the user to disable these built-in classes if they want.
There was a problem hiding this comment.
I can add these. Not sure what is the best way to disable it. Another flag? cc: @msridhar if you have any suggestions.
There was a problem hiding this comment.
Another option is to treat flag as an override and not an addition. The developers may have to pass all these base classes themselves. Con - The callers need to be aware of all the base cases. Pros - Simple.
There was a problem hiding this comment.
Went with 2nd as it is much simpler and requirements for different projects can be different. cf07e46
|
|
||
| /** | ||
| * Checker for subscriptions not binding to lifecycle in components with lifecycle. | ||
| * Use -XepOpt:AutoDisposeLeakCheck to add support for custom components with lifecycle. |
There was a problem hiding this comment.
Let's add a more fleshed out example for things like Conductor in a <code><pre> block
There was a problem hiding this comment.
There are no code changes. These are just changes for build.gradle. Not sure if this will be the correct place. Maybe we should remove this line also.
There was a problem hiding this comment.
Even a one liner is useful. This is a correct place for an example. We can also have a more fleshed out one in the wiki page.
| ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class); | ||
| Type.ClassType enclosingClassType = ASTHelpers.getType(enclosingClass); | ||
|
|
||
| for (String s : classesWithLifecycle) { |
There was a problem hiding this comment.
We can use a java 8 stream here
| return false; | ||
| } | ||
|
|
||
| for (MethodMatchers.MethodNameMatcher nameMatcher : AS_CALL_MATCHERS) { |
| import org.junit.runners.JUnit4; | ||
|
|
||
| @RunWith(JUnit4.class) | ||
| @SuppressWarnings("CheckTestExtendsBaseClass") |
There was a problem hiding this comment.
Remove this, copy-pasta from internal
There was a problem hiding this comment.
Cool. Please make this a separate commit in the future though, that commit was mostly unrelated changes
| tags = {BugPattern.StandardTags.CONCURRENCY}, | ||
| severity = ERROR | ||
| ) | ||
| public final class MissingAutoDisposeErrorChecker extends BugChecker |
There was a problem hiding this comment.
Assuming the AutoDisposeLeakCheck name sticks, we should call this AutoDisposeLeakChecker
|
|
||
| @RunWith(JUnit4.class) | ||
| @SuppressWarnings("CheckTestExtendsBaseClass") | ||
| public class MissingAutoDisposeErrorCheckerTest { |
There was a problem hiding this comment.
Let's call this AutoDisposeLeakCheckerTest
| } | ||
|
|
||
| @Test | ||
| public void test_autodisposePositiveCases2() { |
There was a problem hiding this comment.
Can we call this something more descriptive? Or at least have comments explaining what these two cases are verifying?
There was a problem hiding this comment.
47c35ce. Calling them default for default lifecycle and custom when input is provided.
There was a problem hiding this comment.
Cool, but please make this a separate commit next time. That commit's message/desc mentioned nothing about the descriptive method changes
| */ | ||
| @AutoService(BugChecker.class) | ||
| @BugPattern( | ||
| name = "MissingAutoDisposeErrorChecker", |
There was a problem hiding this comment.
This should be AutoDisposeLeakCheck right? Not sure if I'm missing how these are conventionally done CC @msridhar
There was a problem hiding this comment.
It is not AutoDisposeLeakChecker. 47c35ce
There was a problem hiding this comment.
I'm curious to know why you picked a 3rd new name. Checker should not be part of the name. Thinking more on this, let's call the bugpattern name MissingAutoDispose, and also call the class that
|
The parallelflowable change is merged now if you want to rebase |
|
@bangarharshit are you planning to finisht this? |
|
@hzsweers Sorry was busy with another thing. I am getting weird issues with the build for android projects (it is working fine for normal java projects as an apt). Strangely, I am getting a similar issue for even normal java project after migrating to java-library. Something similar to - google/error-prone#730. I will try to resolve this issue over the weekend. I can address the rest of the comments and then solely look on the build related issues. |
|
Sounds good, I'm likely going to cut a new release without waiting for this one in the meantime |
Error prone flag added to support components with custom lifecycle Removed unused dependencies
d4883cc to
a9bf402
Compare
|
Merge parallel flowable changes and there was a bug when superclass constructor is invoked it is not MemberSelectTree. Will update the wiki in sometime. |
…on can also contains lint related details in the future
README.md
Outdated
|
|
||
| Snapshots of the development version are available in [Sonatype's snapshots repository][snapshots]. | ||
|
|
||
| Static code analysis |
There was a problem hiding this comment.
just call this Static Analysis. Also, please move this to above the Download section
| @@ -49,7 +49,7 @@ | |||
| @AutoService(BugChecker.class) | |||
There was a problem hiding this comment.
In the future, this commit should have been two commits. One for the parallelflowable support, and another for the naming convention cleanups
settings.gradle
Outdated
| include 'autodispose-rxlifecycle' | ||
| include ':sample' | ||
| include ':test-utils' | ||
| include ':tooling:autodispose-error-prone-checker' |
There was a problem hiding this comment.
Let's rename tooling to static-analysis. I suspect you borrowed the tooling convention from the internal monorepo, but there's not actually any build tooling here
There was a problem hiding this comment.
Also changing the name in gradle.properties for the artifact.
There was a problem hiding this comment.
No the artifact name is fine. Only the directory needs to change
Do you have a time frame for that? I'd like to have that in place before merging this |
|
I don't have the permission to update the wiki. Since Github doesn't support PR for the wiki, can you enable wiki edit for me? |
…ference for filtering
| @AutoService(BugChecker.class) | ||
| @BugPattern( | ||
| name = "AutoDisposeLeakChecker", | ||
| summary = "Always apply an AutoDispose scope before subscribing", |
There was a problem hiding this comment.
Let's flesh this out to mention that this is only when running in lifecycle scopes.
| @BugPattern( | ||
| name = "AutoDisposeLeakChecker", | ||
| summary = "Always apply an AutoDispose scope before subscribing", | ||
| tags = {BugPattern.StandardTags.CONCURRENCY}, |
There was a problem hiding this comment.
This doesn't need braces since it's one element. Also static import CONCURRENCY
| */ | ||
| @AutoService(BugChecker.class) | ||
| @BugPattern( | ||
| name = "AutoDisposeLeakChecker", |
There was a problem hiding this comment.
I left a comment somewhere that I can't find now, but let's call both the bugpattern name and the class UseAutoDispose. Don't have Checker as a suffix anywhere. This matches the error-prone convention
There was a problem hiding this comment.
I think maybe that comment wasn't published because I never saw that. Error-prone doesn't have a common stand against it - https://github.com/google/error-prone/blob/master/core/src/main/java/com/google/errorprone/bugpatterns/CompileTimeConstantChecker.java. Fixing it for this case. Maybe you meant this comment - #156 (comment).
Renaming this class for the fourth time based on feedback from PR (RxJavAutoMissingDisposeLeakChecker - MissingAutoDisposeLeakChecker -AutoDisposeLeakChecker - UseAutoDispose).
|
I think this looks good. Do you want to make a separate PR with the wiki contents (won't merge it, but just something we can review here), then I'll paste them into the wiki when that's done? Also, after this is release, we should remove the one in uber/ribs and make it depend on this |
|
Thanks! |
This is a copy of the check from Uber/Ribs with 2 major differences:
asbased API.Things to do:
ParallelFlowable.Fixes - #152