Matt's Tidbits #42 - The answer to the Ultimate Question of Life, the Universe, and Everything…
Tags: mattstidbits, android, androidstudio, lint
Published: 2019-11-12 15:40:38

... or at least why Android Lint is crashing

[In my last post I showed you how to convert a `BehaviorRelay` into a `PublishRelay`.](https://medium.com/@matthew.b.groves/matts-tidbits-41-converting-a-behaviorrelay-into-a-publishrelay-f1084c64fbd) This week I have a very special post with the answer to the Ultimate Question — why is Android Lint crashing on some files?

Last week I refactored some code and discovered that my PR builds were failing on our continuous integration server due to a lint error. Upon closer inspection, I discovered the following error:

```
./gradlew lintDebug

> Task :app:lintDebug FAILED
java.lang.NullPointerException
        at com.intellij.psi.impl.compiled.ClsFileImpl.getMirror(ClsFileImpl.java:345)
        at com.intellij.psi.impl.compiled.ClsElementImpl.getMirror(ClsElementImpl.java:159)
        at com.intellij.psi.impl.compiled.ClsElementImpl.getText(ClsElementImpl.java:202)
        at com.intellij.psi.impl.source.resolve.graphInference.InferenceSession.argConstraints(InferenceSession.java:1863)
.
.
.
(stack trace abbreviated for this article)
FAILURE: Build failed with an exception.

* What went wrong:
Errors found:
  
  /Users/matthew.b.groves/StudioProjects/LintErrorExample/app/src/main/java/com/mpeng3/linterrorexample/MainActivity.java: Error: Unexpected failure during lint analysis of MainActivity.java (this is a bug in lint or one of the libraries it depends on)
  
  
  The crash seems to involve the detector com.android.tools.lint.checks.ApiDetector.
  You can try disabling it with something like this:
      android {
          lintOptions {
              disable "InlinedApi", "ObsoleteSdkInt", "Override", "NewApi", "UnusedAttribute"
          }
      }
```

Whoa — I had never seen this before! Initially I just ignored this by adding it to our `lint-baseline.xml` file (I didn’t want to ignore the all-important ApiDetector lint check — if you’re not familiar with it, go [check it out](https://static.javadoc.io/com.android.tools.lint/lint-checks/24.2.2/com/android/tools/lint/checks/ApiDetector.html)!), but with some prompting from a teammate I dug in a little deeper to figure out what was causing this.

My teammate had a suspicion about what might be causing this, but to get to the bottom of this and figure out exactly what was causing the error I began by commenting out all of the lines of code I had just refactored and started uncommenting them and re-running lint incrementally until I uncovered which line of code was the source of the error:

{% gist https://gist.github.com/mpeng3/967ac8078656e4453b0cb7c1469251b4
%}

I finally narrowed it down — it was the code on line 16. However, this is not the whole contents of this class. The code above on its own is fine. However, if you add the following method to your class, you’ll see the issue:

{% gist https://gist.github.com/mpeng3/77ef0b62659d22195a640aa523b6e610
%}

What are we looking at here? Well, we’re seeing an *overloaded* version of our static method `foo` that has a different signature. This code will compile, but lint runs into problems when trying to check whether any of the contained code uses Android APIs that aren’t supported by the version(s) of Android our app is targeting.

You may also be wondering, what is that slightly strange syntax in line 16 of the first example? Java calls this a [Method Reference](https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html), and it was first introduced as part of Java 8’s support for lambda functions. This is a simpler way of writing the following lambda:

`foo(() -> getIntSingle()).subscribe();`

Method references are a little nicer to read, right? I also think it’s easier to not have to type the parentheses and arrow. And, Android Studio will even show you a lint warning telling you could convert this to a method reference. Ironically, the longer version here does *not* trigger the same lint crash as the method reference version.

So, where do we go from here? This is clearly a bug in lint, and I don’t want to have to ignore lint checks in this file. The good news is, we have a couple of different options:

1. The easiest solution is to rename our `foo` methods so they have different names and aren’t overloads of each other. And, as the official Java documentation on methods points out: [“Overloaded methods should be used sparingly, as they can make code much less readable.”](https://docs.oracle.com/javase/tutorial/java/javaOO/methods.html)

2. Convert the occurrence of the `foo` method that takes an `RxGetter<T>` to instead take a `Single<T>` directly. In my case, I can do this as I’m interacting with “cold” observables. It seems that lint is getting confused and can’t tell when it should use the `Runnable` vs. `RxGetter<T>` version of `foo` — changing one of them to take a `Single<T>` makes it easier for lint to distinguish between them.

3. Just using the longer lambda syntax (and suppressing those lint warnings).

4. Wrapping the method reference with some other method call which then wraps it with the longer lambda syntax so you only have to suppress the “convert to method reference” lint warning in a single place in the code, or executing the method reference so you get direct access to the `Single<T>`, etc.

Whatever you choose though, the most important part is to file a bug against Android Studio (I previously wrote a [tidbit](https://medium.com/@matthew.b.groves/matts-tidbits-2-aa72d3d938ad) about filing bugs, but there’s a new process — now the best way is to click “Help->Submit Feedback” from within Android Studio, which will auto-populate the bug ticket with information about your environment). You can view the bug I filed here:

https://issuetracker.google.com/issues/143971679

Please click the link above and ⭐️ this issue if you’d like to see it fixed!

And, if you’d like to see this for yourself, you can check out this sample project I created:

{% github mpeng3/LintErrorExample %}

Have other ideas about how to resolve this? Leave a comment below! And, please follow me on Medium if you’re interested in being notified of future tidbits.

Interested in joining the awesome team here at Intrepid? [We’re hiring!](https://www.intrepid.io/careers)

*This tidbit was discovered on November 6, 2019.*