2424import spoon .reflect .code .CtArrayWrite ;
2525import spoon .reflect .code .CtAssignment ;
2626import spoon .reflect .code .CtBinaryOperator ;
27+ import spoon .reflect .code .CtBlock ;
2728import spoon .reflect .code .CtConditional ;
2829import spoon .reflect .code .CtConstructorCall ;
2930import spoon .reflect .code .CtExpression ;
3637import spoon .reflect .code .CtNewArray ;
3738import spoon .reflect .code .CtNewClass ;
3839import spoon .reflect .code .CtReturn ;
40+ import spoon .reflect .code .CtStatement ;
3941import spoon .reflect .code .CtThisAccess ;
4042import spoon .reflect .code .CtUnaryOperator ;
4143import spoon .reflect .code .CtVariableAccess ;
@@ -336,18 +338,30 @@ public void visitCtIf(CtIf ifElement) {
336338 CtExpression <Boolean > exp = ifElement .getCondition ();
337339 Predicate expRefs = getExpressionRefinements (exp );
338340
339- String freshVarName = String .format (Formats .FRESH , context .getCounter ());
340- expRefs = expRefs .substituteVariable (Keys .WILDCARD , freshVarName );
341- Predicate lastExpRefs = substituteAllVariablesForLastInstance (expRefs );
342- expRefs = Predicate .createConjunction (expRefs , lastExpRefs );
341+ String pathVarName ;
342+ RefinedVariable freshRV ;
343+ if (isUninformativeCondition (expRefs , exp )) {
344+ // No refinement means the condition is unknown, not true.
345+ String conditionVarName = String .format (Formats .FRESH , context .getCounter ());
346+ context .addInstanceToContext (conditionVarName , factory .Type ().BOOLEAN_PRIMITIVE , new Predicate (), exp );
347+ expRefs = Predicate .createVar (conditionVarName );
348+
349+ pathVarName = String .format (Formats .FRESH , context .getCounter ());
350+ freshRV = context .addInstanceToContext (pathVarName , factory .Type ().BOOLEAN_PRIMITIVE , expRefs , exp );
351+ } else {
352+ pathVarName = String .format (Formats .FRESH , context .getCounter ());
353+ expRefs = expRefs .substituteVariable (Keys .WILDCARD , pathVarName );
354+ Predicate lastExpRefs = substituteAllVariablesForLastInstance (expRefs );
355+ expRefs = Predicate .createConjunction (expRefs , lastExpRefs );
356+
357+ freshRV = context .addInstanceToContext (pathVarName , factory .Type ().INTEGER_PRIMITIVE , expRefs , exp );
358+ }
343359
344360 // TODO Change in future
345361 if (expRefs .getVariableNames ().contains ("null" )) {
346362 expRefs = new Predicate ();
347363 }
348364
349- RefinedVariable freshRV = context .addInstanceToContext (freshVarName , factory .Type ().INTEGER_PRIMITIVE , expRefs ,
350- exp );
351365 vcChecker .addPathVariable (freshRV );
352366
353367 context .variablesNewIfCombination ();
@@ -357,19 +371,23 @@ public void visitCtIf(CtIf ifElement) {
357371 // VISIT THEN
358372 context .enterContext ();
359373 visitCtBlock (ifElement .getThenStatement ());
360- context .variablesSetThenIf ();
374+ if (canCompleteNormally (ifElement .getThenStatement ())) {
375+ context .variablesSetThenIf ();
376+ }
361377 contextHistory .saveContext (ifElement .getThenStatement (), context );
362378 context .exitContext ();
363379
364380 // VISIT ELSE
365381 if (ifElement .getElseStatement () != null ) {
366- context .getVariableByName (freshVarName );
382+ context .getVariableByName (pathVarName );
367383 // expRefs = expRefs.negate();
368- context .newRefinementToVariableInContext (freshVarName , expRefs .negate ());
384+ context .newRefinementToVariableInContext (pathVarName , expRefs .negate ());
369385
370386 context .enterContext ();
371387 visitCtBlock (ifElement .getElseStatement ());
372- context .variablesSetElseIf ();
388+ if (canCompleteNormally (ifElement .getElseStatement ())) {
389+ context .variablesSetElseIf ();
390+ }
373391 contextHistory .saveContext (ifElement .getElseStatement (), context );
374392 context .exitContext ();
375393 }
@@ -380,6 +398,42 @@ public void visitCtIf(CtIf ifElement) {
380398 context .variablesFinishIfCombination ();
381399 }
382400
401+ /**
402+ * Returns true when a condition's refinement gives no useful information about which branch may run.
403+ */
404+ private boolean isUninformativeCondition (Predicate conditionRefinement , CtExpression <Boolean > condition ) {
405+ if (!conditionRefinement .isBooleanTrue ()) {
406+ return false ;
407+ }
408+ if (condition instanceof CtLiteral <?> literal && literal .getValue () instanceof Boolean ) {
409+ return false ;
410+ }
411+ return true ;
412+ }
413+
414+ /**
415+ * Best-effort normal-completion check for branch joins. Branches that end in {@code return} cannot contribute state
416+ * to the code following the {@code if}.
417+ */
418+ private boolean canCompleteNormally (CtStatement statement ) {
419+ if (statement == null ) {
420+ return true ;
421+ }
422+ if (statement instanceof CtReturn <?>) {
423+ return false ;
424+ }
425+ if (statement instanceof CtBlock <?> block ) {
426+ List <CtStatement > statements = block .getStatements ();
427+ return statements .isEmpty () || canCompleteNormally (statements .get (statements .size () - 1 ));
428+ }
429+ if (statement instanceof CtIf nestedIf ) {
430+ CtStatement elseStatement = nestedIf .getElseStatement ();
431+ return canCompleteNormally (nestedIf .getThenStatement ()) || elseStatement == null
432+ || canCompleteNormally (elseStatement );
433+ }
434+ return true ;
435+ }
436+
383437 @ Override
384438 public <T > void visitCtArrayWrite (CtArrayWrite <T > arrayWrite ) {
385439 super .visitCtArrayWrite (arrayWrite );
0 commit comments