google / error-prone

Catch common Java mistakes as compile-time errors
https://errorprone.info
Apache License 2.0
6.77k stars 733 forks source link

Detect potential updates to Immutable collections #229

Open cushon opened 9 years ago

cushon commented 9 years ago

Original issue created by opinali@google.com on 2014-02-03 at 06:31 PM


Error pattern:

public List<Stuff> getMyStuff() {   List<Stuff> list = nastyDao.list();   return list == null // rare condition     ? ImmutableList.of()     : list; }

void x() {   List<Stuff> stuff = getMyStuff();   if (another rare condition) {     stuff.add(new Stuff());   }   ... }

Two problems here. First, getMyStuff() should not have any code path that returns an immutable collection if its return type is just List. Ideally this should be detected even with "return Collections.emptyList()", which unfortunately is wildly abused as an optimization for "return new ArrayList<>()" because there's no allocation but it's not always a valid replacement. In code using Guava I see "ImmutableXxx.of()" sometimes abused in the same way. But there are other subtle cases, such as calling many Guava utilities like Maps.uniqueIndex(), Iterables.filter() and others that are easy to forget that produce an immutable result (because there's no explicit "immutable" in the class or method name, although there is in the return type).

Second variant, suppose the problem above is fixed by making getMyStuff() return ImmutableList. Now x() is buggy. This is the call-side version of the same problem. Generally, I'd like error-prone to propagate information about immutable collections, and detect attempts to assign ImmutableX to X (potential bug that should get a waring) or to invoke mutating methods on Immutable collections (the case in x(), should result in error, notice that it would often be possible to detect this even through temps like the "List stuff" dropping the immutable type).

cushon commented 9 years ago

Original comment posted by lowasser@google.com on 2014-02-03 at 06:35 PM


I don't think I buy that methods returning an immutable or unmodifiable List should be forced to declare that in their return type, but I could get behind making it an error to return a mix of mutable and immutable types, in cases where that could be feasibly detected.

With regard to the second issue, I don't think there's any facility in error-prone to "propagate information" across files in any way.

cushon commented 9 years ago

Original comment posted by jeremymanson@google.com on 2014-02-03 at 06:50 PM


You would probably want type annotations to do this. For example:

http://types.cs.washington.edu/checker-framework/current/checkers-manual.html#igj-checker

cushon commented 9 years ago

Original comment posted by opinali@google.com on 2014-02-03 at 07:15 PM


On methods being forced to declare immutable returns, agree, I think this check (if possible) must be conservative in cases like overrides, and yes the case of mixed returns is the most likely to be a problem and still it should be a warning or optional check. For one thing it would be a great tool if I want to enforce the vision that Guava's Immutable* are "interfaces in every important sense of the word".

On type propagation, yes ideally this should be whole-program flow but I think even making this check within a single method (if the error-prone framework makes that easy enough) would be of great value.

cushon commented 9 years ago

Original comment posted by eaftan@google.com on 2014-03-04 at 12:50 AM


I agree with Jeremy that the right way to do this is probably to use type annotations/the Checker Framework. We have support for running the Checker Framework at Google, but currently only for the nullness checker.

Liam is working on better support for the Checker Framework. He'll follow up when it's getting to a better state.


Status: Accepted Owner: cushon@google.com Labels: -Priority-Medium, Priority-Low

cushon commented 7 years ago

There's some limited support for this in http://errorprone.info/bugpattern/ImmutableModification.