|
| 1 | +/** |
| 2 | + * Finds method calls where the result of the call is ignored, despite the method being |
| 3 | + * annotated with `@CheckReturnValue`. |
| 4 | + * |
| 5 | + * See also Error Prone pattern [CheckReturnValue](https://errorprone.info/bugpattern/CheckReturnValue). |
| 6 | + * |
| 7 | + * @kind problem |
| 8 | + */ |
| 9 | + |
| 10 | +// This is also detected by IntelliJ IDEA, see https://youtrack.jetbrains.com/issue/IDEA-153192 and https://youtrack.jetbrains.com/issue/IDEA-158576 |
| 11 | + |
| 12 | +// Similar to CodeQL's `java/return-value-ignored` and `java/ignored-error-status-of-call` |
| 13 | + |
| 14 | +import java |
| 15 | + |
| 16 | +class CheckReturnValueAnnotation extends Annotation { |
| 17 | + CheckReturnValueAnnotation() { |
| 18 | + // Note: Ignore package name because annotation exists for JSR 305, Error Prone annotations, and SpotBugs annotations, ... |
| 19 | + getType().hasName("CheckReturnValue") |
| 20 | + } |
| 21 | +} |
| 22 | + |
| 23 | +class CanIgnoreReturnValueAnnotation extends Annotation { |
| 24 | + CanIgnoreReturnValueAnnotation() { |
| 25 | + // Note: Currently seems to only exist for Error Prone annotations, but to avoid false positives ignore the |
| 26 | + // package name here as well |
| 27 | + getType().hasName("CanIgnoreReturnValue") |
| 28 | + } |
| 29 | +} |
| 30 | + |
| 31 | +from MethodAccess call, Method m, RefType declaringType |
| 32 | +where |
| 33 | + // Result of method call is ignored |
| 34 | + call instanceof ValueDiscardingExpr |
| 35 | + and m = call.getMethod().getSourceDeclaration() |
| 36 | + and declaringType = m.getDeclaringType() |
| 37 | + // Ignore if method has no return value (but declaring type might be annotated with CheckReturnValue) |
| 38 | + and not m.getReturnType() instanceof VoidType |
| 39 | + and ( |
| 40 | + m.getAnAnnotation() instanceof CheckReturnValueAnnotation |
| 41 | + or |
| 42 | + not m.getAnAnnotation() instanceof CanIgnoreReturnValueAnnotation |
| 43 | + and ( |
| 44 | + declaringType.getAnAnnotation() instanceof CheckReturnValueAnnotation |
| 45 | + or ( |
| 46 | + declaringType.getPackage().getAnAnnotation() instanceof CheckReturnValueAnnotation |
| 47 | + and not declaringType.getAnAnnotation() instanceof CanIgnoreReturnValueAnnotation |
| 48 | + ) |
| 49 | + ) |
| 50 | + ) |
| 51 | + // Ignore test classes |
| 52 | + // TODO: If possible make this more specific; there are cases where results in test classes |
| 53 | + // are relevant as well, for example incorrect usage of AssertJ |
| 54 | + and not call.getEnclosingCallable().getDeclaringType() instanceof TestClass |
| 55 | +select call, "Result of this call should not be ignored" |
0 commit comments