1 package com.uber.nullaway.handlers; 2 3 import com.google.common.base.Preconditions; 4 import com.google.errorprone.util.ASTHelpers; 5 import com.sun.source.tree.MethodInvocationTree; 6 import com.sun.tools.javac.code.Symbol; 7 import com.uber.nullaway.dataflow.cfg.NullAwayCFGBuilder; 8 import javax.annotation.Nullable; 9 import javax.lang.model.element.Name; 10 import javax.lang.model.type.TypeMirror; 11 import org.checkerframework.nullaway.dataflow.cfg.node.MethodInvocationNode; 12 13 /** 14 * Handler to expose semantics of Guava routines like {@code checkState}, {@code checkArgument}, and 15 * {@code verify} that check a boolean condition and fail with an exception if it is false. 16 */ 17 public class GuavaAssertionsHandler extends BaseNoOpHandler { 18 19 private static final String PRECONDITIONS_CLASS_NAME = "com.google.common.base.Preconditions"; 20 private static final String CHECK_ARGUMENT_METHOD_NAME = "checkArgument"; 21 private static final String CHECK_STATE_METHOD_NAME = "checkState"; 22 private static final String VERIFY_CLASS_NAME = "com.google.common.base.Verify"; 23 private static final String VERIFY_METHOD_NAME = "verify"; 24 25 @Nullable private Name preconditionsClass; 26 @Nullable private Name verifyClass; 27 @Nullable private Name checkArgumentMethod; 28 @Nullable private Name checkStateMethod; 29 @Nullable private Name verifyMethod; 30 @Nullable TypeMirror preconditionCheckArgumentErrorType; 31 @Nullable TypeMirror preconditionCheckStateErrorType; 32 @Nullable TypeMirror verifyErrorType; 33 34 @Override onCFGBuildPhase1AfterVisitMethodInvocation( NullAwayCFGBuilder.NullAwayCFGTranslationPhaseOne phase, MethodInvocationTree tree, MethodInvocationNode originalNode)35 public MethodInvocationNode onCFGBuildPhase1AfterVisitMethodInvocation( 36 NullAwayCFGBuilder.NullAwayCFGTranslationPhaseOne phase, 37 MethodInvocationTree tree, 38 MethodInvocationNode originalNode) { 39 Symbol.MethodSymbol callee = ASTHelpers.getSymbol(tree); 40 if (preconditionsClass == null) { 41 preconditionsClass = callee.name.table.fromString(PRECONDITIONS_CLASS_NAME); 42 verifyClass = callee.name.table.fromString(VERIFY_CLASS_NAME); 43 checkArgumentMethod = callee.name.table.fromString(CHECK_ARGUMENT_METHOD_NAME); 44 checkStateMethod = callee.name.table.fromString(CHECK_STATE_METHOD_NAME); 45 verifyMethod = callee.name.table.fromString(VERIFY_METHOD_NAME); 46 preconditionCheckArgumentErrorType = phase.classToErrorType(IllegalArgumentException.class); 47 preconditionCheckStateErrorType = phase.classToErrorType(IllegalStateException.class); 48 // We treat the Verify.* APIs as throwing a RuntimeException to avoid any issues with 49 // the VerifyException that they actually throw not being in the classpath (this will not 50 // affect the analysis result) 51 verifyErrorType = phase.classToErrorType(RuntimeException.class); 52 } 53 Preconditions.checkNotNull(preconditionCheckArgumentErrorType); 54 Preconditions.checkNotNull(preconditionCheckStateErrorType); 55 Preconditions.checkNotNull(verifyErrorType); 56 if (callee.enclClass().getQualifiedName().equals(preconditionsClass) 57 && !callee.getParameters().isEmpty()) { 58 // Attempt to match Precondition check methods to the expected exception type, providing as 59 // much context as possible for static analysis. 60 // In practice this may not be strictly necessary because the conditional throw is inserted 61 // after the method invocation, thus analysis must assume that the preconditions call is 62 // capable of throwing any unchecked throwable. 63 if (callee.name.equals(checkArgumentMethod)) { 64 phase.insertThrowOnFalse(originalNode.getArgument(0), preconditionCheckArgumentErrorType); 65 } else if (callee.name.equals(checkStateMethod)) { 66 phase.insertThrowOnFalse(originalNode.getArgument(0), preconditionCheckStateErrorType); 67 } 68 } else if (callee.enclClass().getQualifiedName().equals(verifyClass) 69 && !callee.getParameters().isEmpty() 70 && callee.name.equals(verifyMethod)) { 71 phase.insertThrowOnFalse(originalNode.getArgument(0), verifyErrorType); 72 } 73 return originalNode; 74 } 75 } 76