• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.uber.nullaway.dataflow;
2 
3 import static com.uber.nullaway.Nullness.NONNULL;
4 import static com.uber.nullaway.Nullness.NULLABLE;
5 
6 import com.google.common.collect.ImmutableSet;
7 import com.sun.source.tree.ClassTree;
8 import com.sun.source.tree.LambdaExpressionTree;
9 import com.sun.source.tree.VariableTree;
10 import com.sun.tools.javac.code.Symbol;
11 import com.sun.tools.javac.code.Types;
12 import com.sun.tools.javac.util.Context;
13 import com.uber.nullaway.Config;
14 import com.uber.nullaway.NullabilityUtil;
15 import com.uber.nullaway.Nullness;
16 import com.uber.nullaway.handlers.Handler;
17 import java.util.List;
18 import java.util.Objects;
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 class CoreNullnessStoreInitializer extends NullnessStoreInitializer {
24 
25   @Override
getInitialStore( UnderlyingAST underlyingAST, List<LocalVariableNode> parameters, Handler handler, Context context, Types types, Config config)26   public NullnessStore getInitialStore(
27       UnderlyingAST underlyingAST,
28       List<LocalVariableNode> parameters,
29       Handler handler,
30       Context context,
31       Types types,
32       Config config) {
33     if (underlyingAST.getKind().equals(UnderlyingAST.Kind.ARBITRARY_CODE)) {
34       // not a method or a lambda; an initializer expression or block
35       UnderlyingAST.CFGStatement ast = (UnderlyingAST.CFGStatement) underlyingAST;
36       return getEnvNullnessStoreForClass(ast.getClassTree(), context);
37     }
38     boolean isLambda = underlyingAST.getKind().equals(UnderlyingAST.Kind.LAMBDA);
39     if (isLambda) {
40       return lambdaInitialStore(
41           (UnderlyingAST.CFGLambda) underlyingAST, parameters, handler, context, types, config);
42     } else {
43       return methodInitialStore(
44           (UnderlyingAST.CFGMethod) underlyingAST, parameters, handler, context, config);
45     }
46   }
47 
methodInitialStore( UnderlyingAST.CFGMethod underlyingAST, List<LocalVariableNode> parameters, Handler handler, Context context, Config config)48   private static NullnessStore methodInitialStore(
49       UnderlyingAST.CFGMethod underlyingAST,
50       List<LocalVariableNode> parameters,
51       Handler handler,
52       Context context,
53       Config config) {
54     ClassTree classTree = underlyingAST.getClassTree();
55     NullnessStore envStore = getEnvNullnessStoreForClass(classTree, context);
56     NullnessStore.Builder result = envStore.toBuilder();
57     for (LocalVariableNode param : parameters) {
58       Element element = param.getElement();
59       Nullness assumed =
60           Nullness.hasNullableAnnotation((Symbol) element, config) ? NULLABLE : NONNULL;
61       result.setInformation(AccessPath.fromLocal(param), assumed);
62     }
63     result = handler.onDataflowInitialStore(underlyingAST, parameters, result);
64     return result.build();
65   }
66 
lambdaInitialStore( UnderlyingAST.CFGLambda underlyingAST, List<LocalVariableNode> parameters, Handler handler, Context context, Types types, Config config)67   private static NullnessStore lambdaInitialStore(
68       UnderlyingAST.CFGLambda underlyingAST,
69       List<LocalVariableNode> parameters,
70       Handler handler,
71       Context context,
72       Types types,
73       Config config) {
74     // include nullness info for locals from enclosing environment
75     EnclosingEnvironmentNullness environmentNullness =
76         EnclosingEnvironmentNullness.instance(context);
77     NullnessStore environmentMapping =
78         Objects.requireNonNull(
79             environmentNullness.getEnvironmentMapping(underlyingAST.getLambdaTree()),
80             "no environment stored for lambda");
81     NullnessStore.Builder result = environmentMapping.toBuilder();
82     LambdaExpressionTree code = underlyingAST.getLambdaTree();
83     // need to check annotation for i'th parameter of functional interface declaration
84     Symbol.MethodSymbol fiMethodSymbol = NullabilityUtil.getFunctionalInterfaceMethod(code, types);
85     com.sun.tools.javac.util.List<Symbol.VarSymbol> fiMethodParameters =
86         fiMethodSymbol.getParameters();
87     ImmutableSet<Integer> nullableParamsFromHandler =
88         handler.onUnannotatedInvocationGetExplicitlyNullablePositions(
89             context, fiMethodSymbol, ImmutableSet.of());
90 
91     for (int i = 0; i < parameters.size(); i++) {
92       LocalVariableNode param = parameters.get(i);
93       VariableTree variableTree = code.getParameters().get(i);
94       Element element = param.getElement();
95       Nullness assumed;
96       // we treat lambda parameters differently; they "inherit" the nullability of the
97       // corresponding functional interface parameter, unless they are explicitly annotated
98       if (Nullness.hasNullableAnnotation((Symbol) element, config)) {
99         assumed = NULLABLE;
100       } else if (!NullabilityUtil.lambdaParamIsImplicitlyTyped(variableTree)) {
101         // the parameter has a declared type with no @Nullable annotation
102         // treat as non-null
103         assumed = NONNULL;
104       } else {
105         if (NullabilityUtil.isUnannotated(fiMethodSymbol, config)) {
106           // assume parameter is non-null unless handler tells us otherwise
107           assumed = nullableParamsFromHandler.contains(i) ? NULLABLE : NONNULL;
108         } else {
109           assumed =
110               Nullness.hasNullableAnnotation(fiMethodParameters.get(i), config)
111                   ? NULLABLE
112                   : NONNULL;
113         }
114       }
115       result.setInformation(AccessPath.fromLocal(param), assumed);
116     }
117     result = handler.onDataflowInitialStore(underlyingAST, parameters, result);
118     return result.build();
119   }
120 }
121