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