• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.uber.nullaway.dataflow;
2 
3 import com.google.errorprone.util.ASTHelpers;
4 import com.sun.source.tree.ClassTree;
5 import com.sun.source.util.Trees;
6 import com.sun.tools.javac.code.Symbol;
7 import com.sun.tools.javac.code.Types;
8 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
9 import com.sun.tools.javac.util.Context;
10 import com.uber.nullaway.Config;
11 import com.uber.nullaway.handlers.Handler;
12 import java.util.List;
13 import java.util.Objects;
14 import javax.annotation.Nullable;
15 import javax.lang.model.element.NestingKind;
16 import org.checkerframework.nullaway.dataflow.cfg.UnderlyingAST;
17 import org.checkerframework.nullaway.dataflow.cfg.node.LocalVariableNode;
18 
19 /**
20  * An abstract class that allows overriding initialization of nullness store in dataflow. Currently,
21  * {@link CoreNullnessStoreInitializer} is the default dataflow initializer and {@link
22  * com.uber.nullaway.handlers.contract.ContractNullnessStoreInitializer} is the initializer in case
23  * of Contract checking dataflow.
24  */
25 public abstract class NullnessStoreInitializer {
26 
27   /**
28    * An abstract method which returns the initial nullness store for dataflow analysis.
29    *
30    * @param underlyingAST The AST node being matched.
31    * @param parameters list of local variable nodes.
32    * @param handler reference to the handler invoked.
33    * @param context context.
34    * @param types types.
35    * @param config config for analysis.
36    * @return Initial Nullness store.
37    */
getInitialStore( UnderlyingAST underlyingAST, List<LocalVariableNode> parameters, Handler handler, Context context, Types types, Config config)38   public abstract NullnessStore getInitialStore(
39       UnderlyingAST underlyingAST,
40       List<LocalVariableNode> parameters,
41       Handler handler,
42       Context context,
43       Types types,
44       Config config);
45 
46   /**
47    * Returns the nullness info of locals in the enclosing environment for the closest enclosing
48    * local or anonymous class. if no such class, returns an empty {@link NullnessStore}
49    */
getEnvNullnessStoreForClass(ClassTree classTree, Context context)50   protected static NullnessStore getEnvNullnessStoreForClass(ClassTree classTree, Context context) {
51     NullnessStore envStore = NullnessStore.empty();
52     ClassTree enclosingLocalOrAnonymous = findEnclosingLocalOrAnonymousClass(classTree, context);
53     if (enclosingLocalOrAnonymous != null) {
54       EnclosingEnvironmentNullness environmentNullness =
55           EnclosingEnvironmentNullness.instance(context);
56       envStore =
57           Objects.requireNonNull(
58               environmentNullness.getEnvironmentMapping(enclosingLocalOrAnonymous));
59     }
60     return envStore;
61   }
62 
63   @Nullable
findEnclosingLocalOrAnonymousClass( ClassTree classTree, Context context)64   private static ClassTree findEnclosingLocalOrAnonymousClass(
65       ClassTree classTree, Context context) {
66     Symbol.ClassSymbol symbol = ASTHelpers.getSymbol(classTree);
67     // we need this while loop since we can have a NestingKind.NESTED class (i.e., a nested
68     // class declared at the top-level within its enclosing class) nested (possibly deeply)
69     // within a NestingKind.ANONYMOUS or NestingKind.LOCAL class
70     while (symbol.getNestingKind().isNested()) {
71       if (symbol.getNestingKind().equals(NestingKind.ANONYMOUS)
72           || symbol.getNestingKind().equals(NestingKind.LOCAL)) {
73         return Trees.instance(JavacProcessingEnvironment.instance(context)).getTree(symbol);
74       } else {
75         // symbol.owner is the enclosing element, which could be a class or a method.
76         // if it's a class, the enclClass() method will (surprisingly) return the class itself,
77         // so this works
78         symbol = symbol.owner.enclClass();
79       }
80     }
81     return null;
82   }
83 }
84