Add `BugChecker.SwitchExpressionTreeMatcher` to support checking of `switch` expressions
Right now, Error Prone checkers cannot perform checks on switch expressions as there is not yet a BugChecker.SwitchExpressionTreeMatcher interface to override. See also discussion at https://github.com/google/error-prone/issues/3803#issuecomment-1736477471.
I'm not sure if there's a way to do this without overriding visitor methods that only exist on newer JDK versions, which I don't think we can't use until the minimum supported JDK version is increased.
It's possible we can use some combination of reflection or proxies, and that might have acceptable performance.
If that doesn't work, perhaps multi-release jars could help here.
To support this feature while also still supporting running Error Prone on JDK 11, possibly an approach could be taken similar to how GJF supports switch expressions (and other newer constructs):
https://github.com/google/google-java-format/blob/master/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java
https://github.com/google/google-java-format/blob/4ade3471b7978af553f425bfc28b36c425e12a67/core/src/main/java/com/google/googlejavaformat/java/Formatter.java#L154-L166
Upon further thought, this may be a bit ugly to support on JDK 11. The issue is that the matchXXX() methods in the matcher interfaces usually take as an argument a Tree of the relevant type. But here, that type would be SwitchExpressionTree, which does not exist in JDK 11. For backward compatibility Error Prone would have to do something like create its own JDK 11-compatible data type wrapping SwitchExpressionTree, using reflection internally to access its components.
That seems like it could work.
Similarly, I had wondered at some point about providing matchSwitchExpressionTree(Tree switchExpressionTree), which of course would typically require users to cast inside their implementation. That would work well for people who are building with newer JDKs, and for people who don't want to do that, they can use reflection. Either way, I think it would work fine for people who are running under older JDKs. As for how Error Prone calls it, I could see the Java17InputAstVisitor approach, or I could see calling the match method reflectively from within scan (rather than by overriding visitSwitchExpression, which I believe would be trouble similar to that that @msridhar describes)... I think? (Compare a roughly similar approach in NullnessUtils.defaultAction.)
It would be a wart forever, though we could try to partially smooth it over in the future by making a binary-compatible but source-incompatible change of the method to <T extends Tree & SwitchExpressionTree> matchSwitchExpressionTree(T tree). Or we could introduce the interface and method as clearly temporary ("CompatibilityShimSwitchExpressionTreeMatcher" and "compatibilitiyShimMatchSwitchExpressionTree?") so that the prime naming real estate is available for the real thing later. (That approach could also apply to @msridhar 's idea.)
FWIW, it seems Checker Framework has gone with the option of just passing in a Tree to the relevant switch expression method, and then providing utility functions for reflectively accessing the parts of the switch expression:
https://github.com/typetools/checker-framework/blob/7462ab0b61faadb405e751448a2ab7d8094ce456/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java#L2303-L2303
https://github.com/typetools/checker-framework/blob/7462ab0b61faadb405e751448a2ab7d8094ce456/javacutil/src/main/java/org/checkerframework/javacutil/TreeUtilsAfterJava11.java#L353-L353
And they override scan to call into the appropriate method:
https://github.com/typetools/checker-framework/blob/7462ab0b61faadb405e751448a2ab7d8094ce456/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java#L399-L404