Challenge 2 – Unused assignments and conditions predetermined

This code defines a function Cruise.Control which computes a mode for automatically controlling a car speed, given the information provided by sensors on the position and speed of surrounding vehicles. The mode distinguishes various levels of breaking and speeding.

Have a look at the following code and see if you can spot the errors. Once you think you’ve got them all, click on the “Go CodePeer” button to see how well you matched up to CodePeer’s comprehensive and rapid analysis of the same code.

Error line 84: “condition predetermined because (Time_Collision_Rear = +0) is always false”

Here’s how CodePeer helps you coming to this conclusion: CodePeer detects that Time_Collision_Rear cannot be non-negative when Time_Collision_Front is non-negative. (A short-circuit boolean operator is used.) Since they are initialized to -1.0 on lines 70 and 71, they can only be both non-negative if the tests on lines 73 and 77 succeed. CodePeer’s warning indicates that this is not possible. Looking more closely at the variables involved in these tests, we realize that Rear_Speed is wrongly initialized to ST.Speeds (Front) on line 68!

Error line 87: “dead code because (Time_Collision_Front >= 0.0 and then Time_Collision_Rear >= +0) = false”

Here’s how CodePeer helps you coming to this conclusion: Since Time_Collision_Rear and Time_Collision_Front cannot both be non-negative, as seen in the previous warning, the test on line 84 always fails, which makes the block of code starting on line 87 dead.

Error line 111: “unused assignment into Front_Speed”

Here’s how CodePeer helps you coming to this conclusion: Front_Speed is assigned on line 102 but is never used. Looking at where the algorithm is expected to use it, this reveals a bug on line 111 where Front_Speed should be used in place of Rear_Speed.

Error line 121: “condition predetermined because (Rear_Distance < Sec_Dist_Rear) is always false”

Here’s how CodePeer helps you coming to this conclusion: CodePeer detects that Rear_Distance cannot be less than Sec_Dist_Rear on line 121. Indeed, the same test used on line 116 prevents executions where this inequality holds to reach line 121. This is because the ‘or else’ boolean operator on line 115 should be an ‘and then’.

package Cruise is

   type Mode is (Hard_Braking, Braking, Steady, Speeding, Hard_Speeding);
   subtype Speeding_Mode is Mode range Speeding .. Hard_Speeding;
   subtype Braking_Mode is Mode range Hard_Braking .. Braking;
   subtype Soft_Mode is Mode range Braking .. Speeding;

   type Vehicle is (Self, Front, Rear);
   subtype Other_Vehicle is Vehicle range Front .. Rear;

   type Speed is new Natural range 0 .. 200;    --  Speed in km/h
   type Distance is new Natural range 0 .. 200; --  Distance in m

   type Vehicle_Speeds is array (Vehicle) of Speed;
   type Other_Vehicle_Distances is array (Other_Vehicle) of Distance;

   --  Sensors are polled every 100ms to compute the following information
   --  about the position and speed of the vehicle w.r.t. the preceding (Front)
   --  vehicle and the following (Rear) vehicle
   type State is record
      Speeds        : Vehicle_Speeds;
      Distances     : Other_Vehicle_Distances;
      Front_Braking : Boolean;
   end record;

   --  Depending on the respective positions and speeds of the vehicles (self,
   --  preceding and following ones), decide on proper action to take
   function Control (ST : State) return Mode;

end Cruise;

package body Cruise is

   --  Return the distance (in m) covered in 2s at speed S (in km/h)
   function Security_Distance (S : Speed) return Distance is
   begin
      return Distance (S * 5 / 9);
   end Security_Distance;

   --  Prevent collision with preceding vehicle by braking appropriately
   function Control_Braking (Front_Braking : Boolean) return Braking_Mode is
   begin
      if Front_Braking then
         return Hard_Braking;
      else
         return Braking;
      end if;
   end Control_Braking;

   --  Prevent collision with following vehicle by speeding appropriately
   function Control_Speeding
      (Self_Speed     : Speed;
       Front_Distance : Distance) return Speeding_Mode is
   begin
      if Front_Distance < Security_Distance (Self_Speed) then
         return Speeding;
      else
         return Hard_Speeding;
      end if;
   end Control_Speeding;

   --  Optimize position of vehicle w.r.t. preceding and following vehicles
   --  to balance the risks of collision with both vehicles
   function Control_Position (ST : State) return Soft_Mode is
      Front_Speed           : Speed    := ST.Speeds (Front);
      Front_Distance        : Distance := ST.Distances (Front);
      Self_Speed            : Speed    := ST.Speeds (Self);
      Rear_Speed            : Speed    := ST.Speeds (Front);
      Rear_Distance         : Distance := ST.Distances (Rear);
      Time_Collision_Front  : Float    := -1.0;
      Time_Collision_Rear   : Float    := -1.0;
   begin
      if Front_Speed < Self_Speed then
         Time_Collision_Front :=
           Float (Front_Distance) / Float (Self_Speed - Front_Speed);
      end if;
      if Self_Speed < Rear_Speed then
         Time_Collision_Rear :=
           Float (Rear_Distance) / Float (Rear_Speed - Self_Speed);
      end if;
      if Time_Collision_Front < 0.0 and then Time_Collision_Rear < 0.0 then
         --  No risk of collision
         return Steady;
      elsif Time_Collision_Front >= 0.0 and then Time_Collision_Rear >= 0.0
      then
         --  Risk of collision with both preceding and following vehicles
         if Time_Collision_Front < Time_Collision_Rear then
            return Braking;
         else
            return Speeding;
         end if;
      elsif Time_Collision_Front < 0.0 then
         --  Risk of collision with following vehicle only
         return Speeding;
      else
         --  Risk of collision with preceding vehicle only
         return Braking;
      end if;
   end Control_Position;

   function Control (ST : State) return Mode is
      Front_Speed     : Speed    := ST.Speeds (Front);
      Front_Distance  : Distance := ST.Distances (Front);
      Front_Braking   : Boolean  := ST.Front_Braking;
      Self_Speed      : Speed    := ST.Speeds (Self);
      Rear_Speed      : Speed    := ST.Speeds (Rear);
      Rear_Distance   : Distance := ST.Distances (Rear);
      Sec_Dist_Front  : Distance := Security_Distance (Self_Speed);
      Sec_Dist_Rear   : Distance := Security_Distance (Rear_Speed);
   begin
      if Rear_Speed < Self_Speed and then
        Front_Distance < Sec_Dist_Front then
         --  Brake if preceding vehicle is close and we are approaching it
         return Control_Braking (Front_Braking => Front_Braking);
      elsif Self_Speed < Rear_Speed or else
        Rear_Distance < Sec_Dist_Rear then
         --  Speed-up if following vehicle is close and approaching us
         return Control_Speeding (Self_Speed     => Self_Speed,
                                  Front_Distance => Front_Distance);
      elsif Front_Distance < Sec_Dist_Front or else
        Rear_Distance < Sec_Dist_Rear then
         --  Maintain equivalent time-to-impact with preceding and following
         --  vehicles if both are close
         return Control_Position (ST);
      else
         return Steady;
      end if;
   end Control;

end Cruise;