• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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