1010import java .util .stream .Collectors ;
1111import java .util .stream .Stream ;
1212
13+ import liquidjava .diagnostics .categories .ErrorCategory ;
1314import liquidjava .diagnostics .hints .Hint .Kind ;
1415import liquidjava .processor .context .RefinedFunction ;
1516import liquidjava .processor .context .Variable ;
2021import spoon .reflect .reference .CtTypeReference ;
2122
2223/**
23- * Hints for a call made in a state that does not allow it, read from the class's {@link StateMachine}. Each hint only
24- * states what the machine proves, so a suggested sequence of calls always makes the failing call verify.
24+ * Hints for a call made in a state that does not allow it, read from the class's {@link StateMachine}. The error's
25+ * category decides which kinds of hints are given, and each hint only states what the machine proves, so a suggested
26+ * sequence of calls always makes the failing call verify.
2527 */
2628public final class StateHints {
2729
@@ -44,19 +46,23 @@ private StateHints(StateMachine machine, String receiver) {
4446 * the states the receiver can be in before the call
4547 * @param receiver
4648 * the receiver as written in the code
49+ * @param category
50+ * the error's category, or {@code null} if it has none
4751 */
48- public static List <Hint > forCall (StateMachine machine , RefinedFunction call , Set <State > current , String receiver ) {
52+ public static List <Hint > forCall (StateMachine machine , RefinedFunction call , Set <State > current , String receiver ,
53+ ErrorCategory category ) {
4954 if (!machine .models (call ) || current .isEmpty () || machine .allows (current , call ))
5055 return List .of (); // the machine cannot explain why the call failed
5156 Set <State > goal = machine .statesAllowing (call );
5257 if (goal .isEmpty ())
5358 return List .of ();
5459
5560 StateHints hints = new StateHints (machine , receiver );
56- if (hints . isUnknown ( current ) )
61+ if (category == ErrorCategory . UNPROVABLE )
5762 return hints .reachingCalls (call , goal );
58- return Stream .concat (hints .howToReach (current , call , goal ).stream (), hints .allowedCalls (current ).stream ())
59- .toList ();
63+ boolean pathDependent = category == ErrorCategory .PATH_DEPENDENT_STATE ;
64+ return Stream .concat (hints .howToReach (current , call , goal , pathDependent ).stream (),
65+ hints .allowedCalls (current ).stream ()).toList ();
6066 }
6167
6268 /** Nothing is known about the receiver's state: list what leads to a state where {@code call} is allowed */
@@ -74,13 +80,13 @@ private List<Hint> reachingCalls(RefinedFunction call, Set<State> goal) {
7480 "The state of %s is unknown here. To get it to %s, use: %s" , receiver , names (goal ), list (ways ))));
7581 }
7682
77- private List <Hint > howToReach (Set <State > current , RefinedFunction call , Set <State > goal ) {
83+ private List <Hint > howToReach (Set <State > current , RefinedFunction call , Set <State > goal , boolean pathDependent ) {
7884 Optional <List <List <RefinedFunction >>> search = machine .shortestPaths (current , call , MAX_SEQUENCES );
7985 if (search .isEmpty ())
8086 return List .of ();
8187 List <List <RefinedFunction >> sequences = search .get ();
8288 if (sequences .isEmpty ())
83- return machine .complete () ? List .of (unreachable (current , call , goal )) : List .of ();
89+ return machine .complete () ? List .of (unreachable (current , call , goal , pathDependent )) : List .of ();
8490 if (sequences .get (0 ).size () > MAX_SEQUENCE_LENGTH )
8591 return List .of ();
8692 return sequences .stream ().map (sequence -> callSequence (current , sequence )).toList ();
@@ -95,8 +101,8 @@ private Hint callSequence(Set<State> current, List<RefinedFunction> sequence) {
95101 receiver , names (current ), names (reached )));
96102 }
97103
98- private Hint unreachable (Set <State > current , RefinedFunction call , Set <State > goal ) {
99- if (current . size () > 1 )
104+ private Hint unreachable (Set <State > current , RefinedFunction call , Set <State > goal , boolean pathDependent ) {
105+ if (pathDependent )
100106 return new Hint (Kind .PATH_DEPENDENT_STATE , String .format (
101107 "%s can be in %s here, depending on the path taken, and no sequence of calls moves all of them to %s. "
102108 + "Make %s reach this line in the same state on every path" ,
@@ -125,11 +131,6 @@ private List<Hint> allowedCalls(Set<State> current) {
125131 return List .of ();
126132 }
127133
128- /** Whether nothing is known about the state of the receiver */
129- private boolean isUnknown (Set <State > current ) {
130- return current .size () == machine .states ().size ();
131- }
132-
133134 private String call (RefinedFunction method ) {
134135 return receiver + "." + signature (method );
135136 }
0 commit comments