@@ -127,7 +127,8 @@ public <T> void visitCtLocalVariable(CtLocalVariable<T> localVariable) {
127127 if (localVariable .getAssignment () == null ) {
128128 // declaration with no assignment
129129 Optional <Predicate > pred = getRefinementFromAnnotation (localVariable );
130- RefinedVariable v = context .addVarToContext (varName , localVariable .getType (), pred .orElse (new Predicate ()), localVariable );
130+ RefinedVariable v = context .addVarToContext (varName , localVariable .getType (), pred .orElse (new Predicate ()),
131+ localVariable );
131132 getMessageFromAnnotation (localVariable ).ifPresent (v ::setMessage );
132133 } else {
133134 // declaration with assignment
@@ -136,7 +137,7 @@ public <T> void visitCtLocalVariable(CtLocalVariable<T> localVariable) {
136137 if (refinementFound == null ) {
137138 refinementFound = new Predicate ();
138139 }
139- if (!Utils .isPrimitiveType (localVariable .getType ().getQualifiedName ()) && ! Utils . isNullLiteral (e )) {
140+ if (!Utils .isPrimitiveType (localVariable .getType ().getQualifiedName ()) && isNonNullExpr (e )) {
140141 refinementFound = Predicate .createConjunction (refinementFound , Predicate .createNonNullEq ());
141142 }
142143 context .addVarToContext (varName , localVariable .getType (), new Predicate (), e );
@@ -245,6 +246,14 @@ public <T> void visitCtField(CtField<T> f) {
245246 if (v instanceof Variable ) {
246247 ((Variable ) v ).setLocation ("this" );
247248 }
249+ // if the field is not initialized and can be null, add instance to context with null equality refinement
250+ if (f .getAssignment () == null && !Utils .isPrimitiveType (f .getType ().getQualifiedName ())) {
251+ String instanceName = String .format (Formats .INSTANCE , name , context .getCounter ());
252+ Predicate initialRefinement = Predicate .createConjunction (ret .substituteVariable (name , instanceName ),
253+ Predicate .createNullEq ().substituteVariable (Keys .WILDCARD , instanceName ));
254+ context .addInstanceToContext (instanceName , f .getType (), initialRefinement , f );
255+ context .addRefinementInstanceToVariable (name , instanceName );
256+ }
248257 }
249258
250259 @ Override
@@ -261,9 +270,12 @@ public <T> void visitCtFieldRead(CtFieldRead<T> fieldRead) {
261270 }
262271
263272 } else if (context .hasVariable (String .format (Formats .THIS , fieldName ))) {
273+ // resolve to latest instance of this field for flow-sensitive refinement
264274 String thisName = String .format (Formats .THIS , fieldName );
275+ Optional <VariableInstance > ovi = context .getLastVariableInstance (thisName );
276+ String var = ovi .isPresent () ? ovi .get ().getName () : thisName ;
265277 fieldRead .putMetadata (Keys .REFINEMENT ,
266- Predicate .createEquals (Predicate .createVar (Keys .WILDCARD ), Predicate .createVar (thisName )));
278+ Predicate .createEquals (Predicate .createVar (Keys .WILDCARD ), Predicate .createVar (var )));
267279
268280 } else if (fieldRead .getVariable ().getSimpleName ().equals ("length" )) {
269281 String targetName = fieldRead .getTarget ().toString ();
@@ -402,7 +414,7 @@ private void checkAssignment(String name, CtTypeReference<?> type, CtExpression<
402414 refinementFound = new Predicate ();
403415 }
404416 }
405- if (!Utils .isPrimitiveType (type .getQualifiedName ()) && ! Utils . isNullLiteral (assignment )) {
417+ if (!Utils .isPrimitiveType (type .getQualifiedName ()) && isNonNullExpr (assignment )) {
406418 refinementFound = Predicate .createConjunction (refinementFound , Predicate .createNonNullEq ());
407419 }
408420 Optional <VariableInstance > r = context .getLastVariableInstance (name );
@@ -436,6 +448,13 @@ private Predicate getExpressionRefinements(CtExpression<?> element) throws LJErr
436448 return getRefinement (element );
437449 }
438450
451+ private boolean isNonNullExpr (CtExpression <?> exp ) {
452+ if (exp == null || Utils .isNullLiteral (exp ))
453+ return false ;
454+ return exp instanceof CtLiteral <?> || exp instanceof CtConstructorCall <?> || exp instanceof CtNewArray <?>
455+ || exp instanceof CtNewClass <?> || exp instanceof CtThisAccess <?>;
456+ }
457+
439458 private Predicate substituteAllVariablesForLastInstance (Predicate c ) {
440459 Predicate ret = c ;
441460 List <String > ls = c .getVariableNames ();
0 commit comments