1 package com.uber.nullaway.handlers.contract; 2 3 import static com.uber.nullaway.Nullness.NONNULL; 4 import static com.uber.nullaway.Nullness.NULLABLE; 5 6 import com.google.errorprone.util.ASTHelpers; 7 import com.sun.source.tree.ClassTree; 8 import com.sun.source.tree.MethodTree; 9 import com.sun.tools.javac.code.Symbol; 10 import com.sun.tools.javac.code.Types; 11 import com.sun.tools.javac.util.Context; 12 import com.uber.nullaway.Config; 13 import com.uber.nullaway.Nullness; 14 import com.uber.nullaway.dataflow.AccessPath; 15 import com.uber.nullaway.dataflow.NullnessStore; 16 import com.uber.nullaway.dataflow.NullnessStoreInitializer; 17 import com.uber.nullaway.handlers.Handler; 18 import java.util.List; 19 import javax.lang.model.element.Element; 20 import org.checkerframework.nullaway.dataflow.cfg.UnderlyingAST; 21 import org.checkerframework.nullaway.dataflow.cfg.node.LocalVariableNode; 22 23 /** 24 * Nullness Store initializer in case of dataflow for contract check. The nullability of parameters 25 * in this case is determined from @Contract annotation. 26 */ 27 public class ContractNullnessStoreInitializer extends NullnessStoreInitializer { 28 29 @Override getInitialStore( UnderlyingAST underlyingAST, List<LocalVariableNode> parameters, Handler handler, Context context, Types types, Config config)30 public NullnessStore getInitialStore( 31 UnderlyingAST underlyingAST, 32 List<LocalVariableNode> parameters, 33 Handler handler, 34 Context context, 35 Types types, 36 Config config) { 37 assert underlyingAST.getKind() == UnderlyingAST.Kind.METHOD; 38 39 final MethodTree methodTree = ((UnderlyingAST.CFGMethod) underlyingAST).getMethod(); 40 final ClassTree classTree = ((UnderlyingAST.CFGMethod) underlyingAST).getClassTree(); 41 final Symbol.MethodSymbol callee = ASTHelpers.getSymbol(methodTree); 42 final String contractString = ContractUtils.getContractString(callee, config); 43 44 if (contractString == null) { 45 throw new IllegalStateException("expected non-null contractString"); 46 } 47 48 String[] clauses = contractString.split(";"); 49 String[] parts = clauses[0].split("->"); 50 String[] antecedent = parts[0].split(","); 51 52 NullnessStore envStore = getEnvNullnessStoreForClass(classTree, context); 53 NullnessStore.Builder result = envStore.toBuilder(); 54 55 for (int i = 0; i < antecedent.length; ++i) { 56 String valueConstraint = antecedent[i].trim(); 57 58 final LocalVariableNode param = parameters.get(i); 59 final Element element = param.getElement(); 60 61 Nullness assumed = NULLABLE; 62 63 // There are 2 cases when we assume that the parameter is NONNULL 64 // 1. if the contract specifies it as (!null) 65 // 2. if there is no @nullable annotation to the parameter in the function signature 66 if (valueConstraint.equals("!null") 67 || !Nullness.hasNullableAnnotation((Symbol) element, config)) { 68 assumed = NONNULL; 69 } 70 71 result.setInformation(AccessPath.fromLocal(param), assumed); 72 } 73 74 return result.build(); 75 } 76 } 77