google / google/error-prone

Check for AutoOneOf usage

Open
#1,217 3 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
7.2k
Forks
820
Avg merge
5h 9m
Merged PRs (30d)
50

Description

### Description of the problem / feature request:

AutoValue has support for a sort of tagged union in java called [`@AutoOneOf`](https://github.com/google/auto/blob/1339e4038c23b8d667316ac4f179a8dac35685e4/value/userguide/howto.md#-make-a-class-where-only-one-of-its-properties-is-ever-set). The idea is that one switches on a corresponding enum of possible subtypes to gain exhaustiveness checks from the compiler or tools like Error-Prone. There's nothing today however to enforce that these methods are actually called _exclusively_ within a switch block, which seems to be the goal. This can be a safety concern, as in practice all but one of the properties are set but none of them can be defined as nullable (calling one that is not correct will throw)

### Feature requests: what underlying problem are you trying to solve with this feature?

An ideal error prone check for this would just be one that enforces that properties called out of an AutoOneOf class are only called from within the context of a matching enum switch case for that type.

Taking their example:

```java
@AutoOneOf(StringOrInteger.Kind.class)
public abstract class StringOrInteger {
public enum Kind {STRING, INTEGER}
public abstract Kind getKind();

public abstract String string();

public abstract int integer();

public static StringOrInteger ofString(String s) {
return AutoOneOf_StringOrInteger.string(s);
}

public static StringOrInteger ofInteger(int i) {
return AutoOneOf_StringOrInteger.integer(i);
}
}
```

The following would be correct usage:

```java
public class Client {
public String representation(StringOrInteger stringOrInteger) {
switch (stringOrInteger.getKind()) {
case STRING:
return '"' + stringOrInteger.string() + '"';
case INTEGER:
return Integer.toString(stringOrInteger.integer());
}
throw new AssertionError(stringOrInteger.getKind());
}
}
```

And this would be incorrect:

```java
public class Client {
public String representation(StringOrInteger stringOrInteger) {
return '"' + stringOrInteger.string() + '"';
}
}
```

The default case probably should be incorrect too

```java
public class Client {
public String representation(StringOrInteger stringOrInteger) {
switch (stringOrInteger.getKind()) {
default:
return '"' + stringOrInteger.string() + '"';
}
throw new AssertionError(stringOrInteger.getKind());
}
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.