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 assert contractString != null; 45 46 String[] clauses = contractString.split(";"); 47 String[] parts = clauses[0].split("->"); 48 String[] antecedent = parts[0].split(","); 49 50 NullnessStore envStore = getEnvNullnessStoreForClass(classTree, context); 51 NullnessStore.Builder result = envStore.toBuilder(); 52 53 for (int i = 0; i < antecedent.length; ++i) { 54 String valueConstraint = antecedent[i].trim(); 55 56 final LocalVariableNode param = parameters.get(i); 57 final Element element = param.getElement(); 58 59 Nullness assumed = NULLABLE; 60 61 // There are 2 cases when we assume that the parameter is NONNULL 62 // 1. if the contract specifies it as (!null) 63 // 2. if there is no @nullable annotation to the parameter in the function signature 64 if (valueConstraint.equals("!null") 65 || !Nullness.hasNullableAnnotation((Symbol) element, config)) { 66 assumed = NONNULL; 67 } 68 69 result.setInformation(AccessPath.fromLocal(param), assumed); 70 } 71 72 return result.build(); 73 } 74 } 75