-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset is free software; you can redistribute it and/or modify it
-- under terms of the GNU General Public License as published by the Free
-- Software Foundation; either version 3, or (at your option) any later
-- version. The SPARK toolset is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-- Public License for more details. You should have received a copy of the GNU
-- General Public License distributed with the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

-- Overview:
-- Perform partition flow analysis as follows:
-- 1.  Calculate claimed Rho by examining the partition annotation
-- 2.  Calculate actual Rho by:
--     a. Examining each withed task (adding as imports anything the task suspends on)
--     b. Examining each with interrupt routine (adding as import the PO that encloses
--        the interrupt handler or the user-chosen InterruptStream name if one was given.
-- 3. Compare the claimed and actual Rho relations and report differences.
--    The following are NOT reported:
--     a.  Dependencies on OUT streams or updates of IN streams (must be implicit)
-- 4. Check the actual Rho and claimed Rho for usage errors:
--     a.  All claimed imports get used somewhere
--     b.  All claimed exports get written somewhere
--     c.  All actual exports are mentioned as exports somewhere in claimed Rho
--     d.  All actual imports are mentioned as imports somewhere in claimed Rho
-- 5.  Check that the last statement of the main program is a plain loop if no
--     tasks have been found during the above analysis
--------------------------------------------------------------------------------

separate (FlowAnalyser)
procedure FlowAnalysePartition (Node    : in     STree.SyntaxNode;
                                TheHeap : in out Heap.HeapRecord) is
   FlowErrorsFound : Boolean := False;
   SemErrorsFound  : Boolean;
   EndPosition     : LexTokenManager.Token_Position;
   Dependency_Node : STree.SyntaxNode;

   PartitionRho                                                     : RelationAlgebra.Relation;
   PartitionImports, PartitionExports, ActualImports, ActualExports : SeqAlgebra.Seq;
   ActualRho                                                        : RelationAlgebra.Relation;

   TaskFound : Boolean := False;

   -------------------------------------------------------------------

   procedure CheckLastStatementOfEnvironmentTaskIsPlainLoop
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Node;
   --#        in     STree.Table;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table;
   is
      EndDesigNode, CurrentNode : STree.SyntaxNode;
      LastLoop                  : Dictionary.Symbol;

      function LastStatementFromEndDesignator (Node : STree.SyntaxNode) return STree.SyntaxNode
      --# global in STree.Table;
      is
         Result : STree.SyntaxNode;
      begin
         Result := STree.Child_Node (Current_Node => STree.Parent_Node (Current_Node => Node)); -- pragma_rep
         Result := STree.Next_Sibling (Current_Node => Result); -- declarative_part or seq_of_stat
         if STree.Syntax_Node_Type (Node => Result) /= SP_Symbols.sequence_of_statements then
            Result := STree.Next_Sibling (Current_Node => Result); -- seq_of_stat
         end if;
         Result := STree.Child_Node (Current_Node => Result); -- statement or seq_of_stat
         if STree.Syntax_Node_Type (Node => Result) /= SP_Symbols.statement then
            Result := STree.Next_Sibling (Current_Node => Result); -- statement
         end if;
         return Result;
      end LastStatementFromEndDesignator;

   begin  -- CheckLastStatementOfEnvironmentTaskIsPlainLoop;

      -- In order to report last statements that not plain loops, we need to find the
      -- end designator of the main subprogram.  Node is main_program_declaration.
      -- Grammar:
      -- main_program_declaration
      --             |
      --           {xxx} --- not_overriding_subprogram_body
      --                           |
      --                         {xxx} ---- subprogram_implementation
      --                                              |
      --                                            {xxx} --- designator | hidden_part

      EndDesigNode :=
        STree.Last_Sibling_Of                     -- designator or hidden part
        (Start_Node => STree.Child_Node           -- statements etc
           (STree.Last_Sibling_Of                 -- subprogram implementation
              (Start_Node => STree.Child_Node     -- some subprog anno item
                 (STree.Last_Sibling_Of           -- not_overriding_subprogram_body
                    (Start_Node => STree.Child_Node (Current_Node => Node)))))); -- some main prog anno item

      -- The above is vulnerable to grammar changes so we perform a run time check here:
      -- ASSUME EndDesigNode = designator OR hidden_part
      SystemErrors.RT_Assert
        (C       => STree.Syntax_Node_Type (Node => EndDesigNode) = SP_Symbols.designator
           or else STree.Syntax_Node_Type (Node => EndDesigNode) = SP_Symbols.hidden_part,
         Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Failed to find end designator node in CheckLastStatementOfEnvironmentTaskIsPlainLoop");

      -- We can't do anything about hidden main prgoram, but if there is an end designator then we can check for
      -- the required loop
      if STree.Syntax_Node_Type (Node => EndDesigNode) = SP_Symbols.designator then
         CurrentNode := LastStatementFromEndDesignator (EndDesigNode);
         if STree.Syntax_Node_Type (Node => STree.Child_Node (Current_Node => STree.Child_Node (Current_Node => CurrentNode))) =
           SP_Symbols.loop_statement then
            -- check loop has no exits
            LastLoop := Dictionary.LastMostEnclosingLoop (Dictionary.GetMainProgram);
            if not Dictionary.Is_Null_Symbol (LastLoop) and then Dictionary.GetLoopHasExits (LastLoop) then
               ErrorHandler.Semantic_Error
                 (Err_Num   => 989,
                  Reference => ErrorHandler.No_Reference,
                  Position  => STree.Node_Position (Node => EndDesigNode),
                  Id_Str    => LexTokenManager.Null_String);
            end if;
         else -- last statement not a loop
            ErrorHandler.Semantic_Error
              (Err_Num   => 989,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => EndDesigNode),
               Id_Str    => LexTokenManager.Null_String);
         end if;
      end if;
   end CheckLastStatementOfEnvironmentTaskIsPlainLoop;

   -------------------------------------------------------------------

   function Find_Derives_Node (Node : STree.SyntaxNode) return STree.SyntaxNode
   --# global in STree.Table;
   --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.main_program_declaration;
   --# return Return_Node => STree.Syntax_Node_Type (Return_Node, STree.Table) = SP_Symbols.dependency_relation or
   --#   Return_Node = STree.NullNode;
   is
      Result : STree.SyntaxNode;
   begin
      Result := STree.Child_Node (Current_Node => Node);
      -- ASSUME Result = inherit_clause OR main_program_annotation
      if STree.Syntax_Node_Type (Node => Result) = SP_Symbols.inherit_clause then
         -- ASSUME Result = inherit_clause
         Result := STree.Next_Sibling (Current_Node => Result);
         -- ASSUME Result = main_program_annotation
         SystemErrors.RT_Assert
           (C       => STree.Syntax_Node_Type (Node => Result) = SP_Symbols.main_program_annotation,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Result = main_program_annotation in Find_Derives_Node");
      elsif STree.Syntax_Node_Type (Node => Result) /= SP_Symbols.main_program_annotation then
         Result := STree.NullNode;
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Result = inherit_clause OR main_program_annotation in Find_Derives_Node");
      end if;
      --# check STree.Syntax_Node_Type (Result, STree.Table) = SP_Symbols.main_program_annotation;
      Result := STree.Next_Sibling (Current_Node => Result);
      -- ASSUME Result = moded_global_definition OR not_overriding_subprogram_body
      if STree.Syntax_Node_Type (Node => Result) = SP_Symbols.moded_global_definition then
         -- ASSUME Result = moded_global_definition
         Result := STree.Next_Sibling (Current_Node => Result);
         -- ASSUME Result = dependency_relation OR not_overriding_subprogram_body
         if STree.Syntax_Node_Type (Node => Result) = SP_Symbols.not_overriding_subprogram_body then
            -- ASSUME Result = not_overriding_subprogram_body
            Result := STree.NullNode;
         elsif STree.Syntax_Node_Type (Node => Result) /= SP_Symbols.dependency_relation then
            Result := STree.NullNode;
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Result = dependency_relation OR not_overriding_subprogram_body in Find_Derives_Node");
         end if;
      elsif STree.Syntax_Node_Type (Node => Result) = SP_Symbols.not_overriding_subprogram_body then
         Result := STree.NullNode;
      else
         Result := STree.NullNode;
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Result = moded_global_definition OR not_overriding_subprogram_body in Find_Derives_Node");
      end if;
      return Result;
   end Find_Derives_Node;

   ------------------------------------------------------------------
   -- utilities to simplify adding symbols to sequences and relations
   ------------------------------------------------------------------

   procedure InsertSymbolPair
     (TheHeap    : in out Heap.HeapRecord;
      Rel        : in     RelationAlgebra.Relation;
      Sym1, Sym2 : in     Dictionary.Symbol)
   --# global in out Statistics.TableUsage;
   --# derives Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    Rel,
   --#                                    Sym1,
   --#                                    Sym2,
   --#                                    TheHeap;
   is
   begin
      RelationAlgebra.InsertPair (TheHeap, Rel, Natural (Dictionary.SymbolRef (Sym1)), Natural (Dictionary.SymbolRef (Sym2)));
   end InsertSymbolPair;

   -------------------------------------------------------------

   procedure InsertSymbol (TheHeap : in out Heap.HeapRecord;
                           Seq     : in     SeqAlgebra.Seq;
                           Sym     : in     Dictionary.Symbol)
   --# global in out Statistics.TableUsage;
   --# derives Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    Seq,
   --#                                    Sym,
   --#                                    TheHeap;
   is
   begin
      SeqAlgebra.AddMember (TheHeap, Seq, Natural (Dictionary.SymbolRef (Sym)));
   end InsertSymbol;

   -------------------------------------------------------------
   -- Constructors for main components of partition check
   -------------------------------------------------------------

   -- Calculates the claimed Rho using the partition level derives annotation
   procedure BuildPartitionRho
   --# global in     Dictionary.Dict;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --#           out PartitionExports;
   --#           out PartitionImports;
   --#           out PartitionRho;
   --# derives PartitionExports,
   --#         PartitionImports,
   --#         PartitionRho          from TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    Dictionary.Dict,
   --#                                    TheHeap;
   is
      ExportIt, ImportIt   : Dictionary.Iterator;
      ExportVar, ImportVar : Dictionary.Symbol;
   begin
      -- create the sequences and relation we are calculating
      SeqAlgebra.CreateSeq (TheHeap, PartitionExports);
      SeqAlgebra.CreateSeq (TheHeap, PartitionImports);
      RelationAlgebra.CreateRelation (TheHeap, PartitionRho);
      -- loop through exports and add export/import pairs to Rho
      ExportIt := Dictionary.FirstExport (Dictionary.IsAbstract, Dictionary.GetThePartition);
      while not Dictionary.IsNullIterator (ExportIt) loop
         ExportVar := Dictionary.CurrentSymbol (ExportIt);
         InsertSymbol (TheHeap, PartitionExports, ExportVar);
         ImportIt := Dictionary.FirstDependency (Dictionary.IsAbstract, Dictionary.GetThePartition, ExportVar);
         while not Dictionary.IsNullIterator (ImportIt) loop
            ImportVar := Dictionary.CurrentSymbol (ImportIt);
            InsertSymbol (TheHeap, PartitionImports, ImportVar);
            InsertSymbolPair (TheHeap, PartitionRho, ImportVar, ExportVar);
            ImportIt := Dictionary.NextSymbol (ImportIt);
         end loop;
         ExportIt := Dictionary.NextSymbol (ExportIt);
      end loop;
      -- now loop through all the imports in case any are associated with "null"
      ImportIt := Dictionary.FirstImport (Dictionary.IsAbstract, Dictionary.GetThePartition);
      while not Dictionary.IsNullIterator (ImportIt) loop
         ImportVar := Dictionary.CurrentSymbol (ImportIt);
         InsertSymbol (TheHeap, PartitionImports, ImportVar);
         ImportIt := Dictionary.NextSymbol (ImportIt);
      end loop;
      -- add the data sink NullVariable as an import and an export
      InsertSymbol (TheHeap, PartitionImports, Dictionary.GetNullVariable);
      InsertSymbol (TheHeap, PartitionExports, Dictionary.GetNullVariable);
   end BuildPartitionRho;

   -------------------------------------------------------------
   -- Routines to calculate the actual Rho based on all visible tasks
   -- and interrupt handlers
   -------------------------------------------------------------

   procedure CalculateActualRho
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     EndPosition;
   --#        in     LexTokenManager.State;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --#        in out TaskFound;
   --#        in out TheHeap;
   --#           out ActualExports;
   --#           out ActualImports;
   --#           out ActualRho;
   --#           out SemErrorsFound;
   --# derives ActualExports,
   --#         ActualImports,
   --#         ActualRho                  from TheHeap &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         EndPosition,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         SPARK_IO.File_Sys &
   --#         SemErrorsFound             from Dictionary.Dict &
   --#         Statistics.TableUsage,
   --#         TheHeap                    from *,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         TheHeap &
   --#         TaskFound                  from *,
   --#                                         Dictionary.Dict;
   is

      WithedPackages : Dictionary.Iterator;

      CurrentPackage                 : Dictionary.Symbol;
      CurrentRho                     : RelationAlgebra.Relation;
      CurrentImports, CurrentExports : SeqAlgebra.Seq;
      MainProgram                    : Dictionary.Symbol;
      MainProgramOk                  : Boolean;

      -- Two sets to collect all the actual exports and imports of protected state
      -- at the partition level.
      ProtectedExports, ProtectedImports : SeqAlgebra.Seq;

      ----------------------------------

      procedure GetTaskRho
        (TaskSym          : in     Dictionary.Symbol;
         Rho              :    out RelationAlgebra.Relation;
         Imports, Exports :    out SeqAlgebra.Seq;
         RhoOk            :    out Boolean)
      --# global in     Dictionary.Dict;
      --#        in out Statistics.TableUsage;
      --#        in out TheHeap;
      --# derives Exports,
      --#         Imports,
      --#         Rho                   from TheHeap &
      --#         RhoOk                 from Dictionary.Dict,
      --#                                    TaskSym &
      --#         Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    Dictionary.Dict,
      --#                                    TaskSym,
      --#                                    TheHeap;
      is
         SuspensionIt, ExportIt, ImportIt : Dictionary.Iterator;

         ExportVar, ImportVar       : Dictionary.Symbol;
         RhoLocal                   : RelationAlgebra.Relation;
         TheTask                    : Dictionary.Symbol;
         ImportsLocal, ExportsLocal : SeqAlgebra.Seq;

      begin -- GetTaskRho
         SeqAlgebra.CreateSeq (TheHeap, ImportsLocal);
         SeqAlgebra.CreateSeq (TheHeap, ExportsLocal);
         RelationAlgebra.CreateRelation (TheHeap, RhoLocal);
         RhoOk := True;

         -- We need to use TaskSym directly if it is the main program (a subprogram),
         -- or, if it is a task variable, we need to use its type because that is what
         -- the dependency relation of a task is tied to in the dictionary.
         if Dictionary.IsMainProgram (TaskSym) then
            TheTask := TaskSym;
         else -- a task object
            TheTask := Dictionary.GetRootType (Dictionary.GetType (TaskSym));
         end if;
         if Dictionary.Is_Declared (Item => TheTask)
           and then  -- trap tasks types in hidden pack priv parts
           Dictionary.SubprogramSignatureIsWellformed (Dictionary.IsAbstract, TheTask) then
            ExportIt := Dictionary.FirstExport (Dictionary.IsAbstract, TheTask);
            while not Dictionary.IsNullIterator (ExportIt) loop
               ExportVar := Dictionary.CurrentSymbol (ExportIt);
               InsertSymbol (TheHeap, ExportsLocal, ExportVar);
               -- We add in each thing the task suspends on as an import here because at the
               -- partition level, suspension affects information flow by affecting which
               -- tasks run
               SuspensionIt := Dictionary.FirstSuspendsListItem (TheTask);
               while not Dictionary.IsNullIterator (SuspensionIt) loop
                  InsertSymbolPair (TheHeap, RhoLocal, Dictionary.CurrentSymbol (SuspensionIt), ExportVar);
                  InsertSymbol (TheHeap, ImportsLocal, Dictionary.CurrentSymbol (SuspensionIt));

                  SuspensionIt := Dictionary.NextSymbol (SuspensionIt);
               end loop;

               -- add any explicit imports
               ImportIt := Dictionary.FirstDependency (Dictionary.IsAbstract, TheTask, ExportVar);
               while not Dictionary.IsNullIterator (ImportIt) loop
                  ImportVar := Dictionary.CurrentSymbol (ImportIt);
                  InsertSymbolPair (TheHeap, RhoLocal, ImportVar, ExportVar);
                  InsertSymbol (TheHeap, ImportsLocal, ImportVar);
                  ImportIt := Dictionary.NextSymbol (ImportIt);
               end loop;
               ExportIt := Dictionary.NextSymbol (ExportIt);
            end loop;
         else
            RhoOk := False;
         end if;
         Rho     := RhoLocal;
         Exports := ExportsLocal;
         Imports := ImportsLocal;
      end GetTaskRho;

      ----------------------------------

      procedure GetInterruptRho
        (SubprogSym       : in     Dictionary.Symbol;
         OwnVar           : in     Dictionary.Symbol;
         Rho              :    out RelationAlgebra.Relation;
         Imports, Exports :    out SeqAlgebra.Seq;
         RhoOk            :    out Boolean)
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     LexTokenManager.State;
      --#        in out Statistics.TableUsage;
      --#        in out TheHeap;
      --# derives Exports,
      --#         Imports,
      --#         Rho                   from TheHeap &
      --#         RhoOk                 from Dictionary.Dict,
      --#                                    SubprogSym &
      --#         Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    CommandLineData.Content,
      --#                                    Dictionary.Dict,
      --#                                    LexTokenManager.State,
      --#                                    OwnVar,
      --#                                    SubprogSym,
      --#                                    TheHeap;
      is

         ExportIt, ImportIt         : Dictionary.Iterator;
         ExportVar, ImportVar       : Dictionary.Symbol;
         RhoLocal                   : RelationAlgebra.Relation;
         ImportsLocal, ExportsLocal : SeqAlgebra.Seq;

         -- substitutes the own variable name for the type name in a protected proc.
         function SubstituteProtectedTypeSelfReference (Sym, OwnVar : Dictionary.Symbol) return Dictionary.Symbol
         --# global in Dictionary.Dict;
         is
            Result : Dictionary.Symbol;
         begin
            Result := Sym;
            if Dictionary.IsOwnVariable (Sym) and then Dictionary.IsProtectedType (Dictionary.GetOwner (Sym)) then
               Result := OwnVar;
            end if;
            return Result;
         end SubstituteProtectedTypeSelfReference;

         ---------------------------------------------------------------

      begin --GetInterruptRho
         SeqAlgebra.CreateSeq (TheHeap, ImportsLocal);
         SeqAlgebra.CreateSeq (TheHeap, ExportsLocal);
         RelationAlgebra.CreateRelation (TheHeap, RhoLocal);
         RhoOk := True;
         if Dictionary.SubprogramSignatureIsWellformed (Dictionary.IsAbstract, SubprogSym) then
            ExportIt := Dictionary.FirstExport (Dictionary.IsAbstract, SubprogSym);
            while not Dictionary.IsNullIterator (ExportIt) loop
               ExportVar := Dictionary.CurrentSymbol (ExportIt);
               InsertSymbol (TheHeap, ExportsLocal, SubstituteProtectedTypeSelfReference (ExportVar, OwnVar));
               -- For interrupt handlers, we add the name of the protected object (or the interrupt stream
               -- associated with it as an import;
               -- in effect, we either regard the PO as protecting a notional stream which
               -- represents the "stream" of interrupts being generated by the environment or we use the
               -- user-named interrupt stream as the source of interrupts.
               InsertSymbolPair
                 (TheHeap,
                  RhoLocal,
                  Dictionary.GetInterruptStreamVariable (ProtectedObject  => OwnVar,
                                                         InterruptHandler => SubprogSym), -- the import
                  SubstituteProtectedTypeSelfReference (ExportVar, OwnVar)); -- the export
               InsertSymbol
                 (TheHeap,
                  ImportsLocal,
                  Dictionary.GetInterruptStreamVariable (ProtectedObject  => OwnVar,
                                                         InterruptHandler => SubprogSym));

               -- now add all the actualimports associated with ExportVar
               ImportIt := Dictionary.FirstDependency (Dictionary.IsAbstract, SubprogSym, ExportVar);
               while not Dictionary.IsNullIterator (ImportIt) loop
                  ImportVar := Dictionary.CurrentSymbol (ImportIt);
                  InsertSymbolPair
                    (TheHeap,
                     RhoLocal,
                     SubstituteProtectedTypeSelfReference (ImportVar, OwnVar),
                     SubstituteProtectedTypeSelfReference (ExportVar, OwnVar));
                  InsertSymbol (TheHeap, ImportsLocal, SubstituteProtectedTypeSelfReference (ImportVar, OwnVar));
                  ImportIt := Dictionary.NextSymbol (ImportIt);
               end loop;
               ExportIt := Dictionary.NextSymbol (ExportIt);
            end loop;
         else
            RhoOk := False;
         end if;

         -- assign exports
         Rho     := RhoLocal;
         Exports := ExportsLocal;
         Imports := ImportsLocal;
      end GetInterruptRho;

      ----------------------------------

      procedure ProcessCurrentPackage
        (PackSym                        : in     Dictionary.Symbol;
         Rho                            :    out RelationAlgebra.Relation;
         PackageExports, PackageImports :    out SeqAlgebra.Seq)
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     EndPosition;
      --#        in     LexTokenManager.State;
      --#        in out ErrorHandler.Error_Context;
      --#        in out SemErrorsFound;
      --#        in out SPARK_IO.File_Sys;
      --#        in out Statistics.TableUsage;
      --#        in out TaskFound;
      --#        in out TheHeap;
      --# derives ErrorHandler.Error_Context,
      --#         SPARK_IO.File_Sys          from CommandLineData.Content,
      --#                                         Dictionary.Dict,
      --#                                         EndPosition,
      --#                                         ErrorHandler.Error_Context,
      --#                                         LexTokenManager.State,
      --#                                         PackSym,
      --#                                         SPARK_IO.File_Sys &
      --#         PackageExports,
      --#         PackageImports,
      --#         Rho                        from TheHeap &
      --#         SemErrorsFound,
      --#         TaskFound                  from *,
      --#                                         Dictionary.Dict,
      --#                                         PackSym &
      --#         Statistics.TableUsage,
      --#         TheHeap                    from *,
      --#                                         CommandLineData.Content,
      --#                                         Dictionary.Dict,
      --#                                         LexTokenManager.State,
      --#                                         PackSym,
      --#                                         TheHeap;
      is
         PackageRho, RhoLocal                                                 : RelationAlgebra.Relation;
         PackageImportsLocal, PackageExportsLocal, ImportsLocal, ExportsLocal : SeqAlgebra.Seq;
         RhoLocalOk                                                           : Boolean;
         It, SubprogramIt                                                     : Dictionary.Iterator;
      begin
         SeqAlgebra.CreateSeq (TheHeap, PackageExportsLocal);
         SeqAlgebra.CreateSeq (TheHeap, PackageImportsLocal);
         RelationAlgebra.CreateRelation (TheHeap, PackageRho);
         -- process all the tasks in the package
         It := Dictionary.FirstOwnTask (PackSym);
         while not Dictionary.IsNullIterator (It) loop
            TaskFound := True;
            GetTaskRho
              (TaskSym => Dictionary.CurrentSymbol (It),
               Rho     => RhoLocal,
               Imports => ImportsLocal,
               Exports => ExportsLocal,
               RhoOk   => RhoLocalOk);
            if RhoLocalOk then
               RelationAlgebra.AugmentRelation (TheHeap, PackageRho, RhoLocal);
               SeqAlgebra.AugmentSeq (TheHeap, PackageExportsLocal, ExportsLocal);
               SeqAlgebra.AugmentSeq (TheHeap, PackageImportsLocal, ImportsLocal);
            else
               SemErrorsFound := True;
               ErrorHandler.Semantic_Warning_Sym
                 (Err_Num  => 410,
                  Position => EndPosition,
                  Sym      => Dictionary.CurrentSymbol (It),
                  Scope    => Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                                         The_Unit       => Dictionary.GetMainProgram));
            end if;
            SeqAlgebra.DisposeOfSeq (TheHeap, ImportsLocal);
            SeqAlgebra.DisposeOfSeq (TheHeap, ExportsLocal);
            RelationAlgebra.DisposeOfRelation (TheHeap, RhoLocal);
            It := Dictionary.NextSymbol (It);
         end loop;

         -- process all the interrupts in the package
         It := Dictionary.FirstOwnVariable (PackSym);
         while not Dictionary.IsNullIterator (It) loop
            if Dictionary.GetHasInterruptProperty (Dictionary.CurrentSymbol (It)) then
               -- a protected own variable with an interrupt handler has been found
               if Dictionary.Is_Declared
                 (Item => Dictionary.GetRootType (Dictionary.GetType (Dictionary.CurrentSymbol (It)))) then
                  -- the protected type is not hidden in a hidden package private parts so we can process it
                  SubprogramIt :=
                    Dictionary.First_Visible_Subprogram
                    (The_Package_Or_Type => Dictionary.GetRootType (Dictionary.GetType (Dictionary.CurrentSymbol (It))));
                  while not Dictionary.IsNullIterator (SubprogramIt) loop
                     if Dictionary.IsInterruptHandler (Dictionary.CurrentSymbol (SubprogramIt)) then
                        -- found symbol of an interrupt handling procedure
                        GetInterruptRho
                          (SubprogSym => Dictionary.CurrentSymbol (SubprogramIt),
                           OwnVar     => Dictionary.CurrentSymbol (It),
                           Rho        => RhoLocal,
                           Imports    => ImportsLocal,
                           Exports    => ExportsLocal,
                           RhoOk      => RhoLocalOk);
                        if RhoLocalOk then
                           RelationAlgebra.AugmentRelation (TheHeap, PackageRho, RhoLocal);
                           SeqAlgebra.AugmentSeq (TheHeap, PackageExportsLocal, ExportsLocal);
                           SeqAlgebra.AugmentSeq (TheHeap, PackageImportsLocal, ImportsLocal);
                        else
                           SemErrorsFound := True;
                           ErrorHandler.Semantic_Warning_Sym
                             (Err_Num  => 410,
                              Position => EndPosition,
                              Sym      => Dictionary.CurrentSymbol (It),
                              Scope    => Dictionary.Set_Visibility
                                (The_Visibility => Dictionary.Local,
                                 The_Unit       => Dictionary.GetMainProgram));
                        end if;
                        SeqAlgebra.DisposeOfSeq (TheHeap, ImportsLocal);
                        SeqAlgebra.DisposeOfSeq (TheHeap, ExportsLocal);
                        RelationAlgebra.DisposeOfRelation (TheHeap, RhoLocal);
                     end if;
                     SubprogramIt := Dictionary.NextSymbol (SubprogramIt);
                  end loop;
               else
                  -- the announced protected type is hidden and cannot be processed
                  SemErrorsFound := True;
                  ErrorHandler.Semantic_Warning_Sym
                    (Err_Num  => 410,
                     Position => EndPosition,
                     Sym      => Dictionary.CurrentSymbol (It),
                     Scope    => Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                                            The_Unit       => Dictionary.GetMainProgram));
               end if;
            end if;
            It := Dictionary.NextSymbol (It);
         end loop;

         -- assign exports
         Rho            := PackageRho;
         PackageExports := PackageExportsLocal;
         PackageImports := PackageImportsLocal;
      end ProcessCurrentPackage;

      ----------------------------------

   begin -- CalculateActualRho
      SemErrorsFound := False;
      SeqAlgebra.CreateSeq (TheHeap, ActualExports);
      SeqAlgebra.CreateSeq (TheHeap, ActualImports);
      SeqAlgebra.CreateSeq (TheHeap, ProtectedExports);
      SeqAlgebra.CreateSeq (TheHeap, ProtectedImports);
      RelationAlgebra.CreateRelation (TheHeap, ActualRho);
      -- We need to search all the packages withed by the main program and process
      -- every task therein.

      -- We also need to include the flow relation of the main
      -- program itself which is also a task.
      MainProgram := Dictionary.GetMainProgram;
      GetTaskRho (MainProgram, CurrentRho, CurrentImports, CurrentExports, MainProgramOk);
      if MainProgramOk then
         SeqAlgebra.AugmentSeq (TheHeap, ActualImports, CurrentImports);
         SeqAlgebra.AugmentSeq (TheHeap, ActualExports, CurrentExports);
         RelationAlgebra.AugmentRelation (TheHeap, ActualRho, CurrentRho);
      else
         ErrorHandler.Semantic_Warning_Sym
           (Err_Num  => 410,
            Position => EndPosition,
            Sym      => MainProgram,
            Scope    => Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                                   The_Unit       => MainProgram));
         SemErrorsFound := True;
      end if;
      RelationAlgebra.DisposeOfRelation (TheHeap, CurrentRho);
      SeqAlgebra.DisposeOfSeq (TheHeap, CurrentImports);
      SeqAlgebra.DisposeOfSeq (TheHeap, CurrentExports);

      WithedPackages := Dictionary.FirstInheritsClause (MainProgram);
      while not Dictionary.IsNullIterator (WithedPackages) loop
         CurrentPackage := Dictionary.CurrentSymbol (WithedPackages);
         if Dictionary.Is_Withed
           (The_Withed_Symbol => CurrentPackage,
            Scope             => Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                                            The_Unit       => MainProgram)) then
            ProcessCurrentPackage (CurrentPackage,
                                   -- to get
                                   CurrentRho, CurrentExports, CurrentImports);
            RelationAlgebra.AugmentRelation (TheHeap, ActualRho, CurrentRho);
            RelationAlgebra.DisposeOfRelation (TheHeap, CurrentRho);
            SeqAlgebra.AugmentSeq (TheHeap, ActualExports, CurrentExports);
            SeqAlgebra.AugmentSeq (TheHeap, ActualImports, CurrentImports);
            SeqAlgebra.DisposeOfSeq (TheHeap, CurrentImports);
            SeqAlgebra.DisposeOfSeq (TheHeap, CurrentExports);
         end if;
         WithedPackages := Dictionary.NextSymbol (WithedPackages);
      end loop;
      SeqAlgebra.DisposeOfSeq (TheHeap, ProtectedExports);
      SeqAlgebra.DisposeOfSeq (TheHeap, ProtectedImports);
   end CalculateActualRho;

   -------------------------------------------------------------
   -- Routines to compare the claimed and actual partition flow
   -- relations and issue suitable error messages
   -------------------------------------------------------------

   procedure CompareRelations
   --# global in     ActualRho;
   --#        in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     EndPosition;
   --#        in     LexTokenManager.State;
   --#        in     PartitionExports;
   --#        in     PartitionImports;
   --#        in     PartitionRho;
   --#        in out ErrorHandler.Error_Context;
   --#        in out FlowErrorsFound;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from ActualRho,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         EndPosition,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         PartitionExports,
   --#                                         PartitionImports,
   --#                                         PartitionRho,
   --#                                         SPARK_IO.File_Sys,
   --#                                         TheHeap &
   --#         FlowErrorsFound            from *,
   --#                                         ActualRho,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         PartitionExports,
   --#                                         PartitionImports,
   --#                                         PartitionRho,
   --#                                         TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap                    from *,
   --#                                         ActualRho,
   --#                                         Dictionary.Dict,
   --#                                         PartitionExports,
   --#                                         PartitionRho,
   --#                                         TheHeap;
   is

      DependencyCol, RhoCol : SeqAlgebra.Seq;

      MemberOfExports       : SeqAlgebra.MemberOfSeq;
      ExpVarRep             : Natural;
      ExportVar             : Dictionary.Symbol;
      MemberOfDependencyCol : SeqAlgebra.MemberOfSeq;
      DepRep                : Natural;
      DepSym                : Dictionary.Symbol;
      MemberOfRhoCol        : SeqAlgebra.MemberOfSeq;
      RhoSym                : Dictionary.Symbol;
      RhoRep                : Natural;
      Scope                 : Dictionary.Scopes;

      -- Function introduced to make the body of CompareRelations cleaner
      function IsAnOutStream (Sym : Dictionary.Symbol) return Boolean
      --# global in Dictionary.Dict;
      is
      begin
         return Dictionary.GetOwnVariableOrConstituentMode (Dictionary.GetMostEnclosingObject (Sym)) = Dictionary.OutMode;
      end IsAnOutStream;

   begin --CompareRelations
      Scope           := Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                                    The_Unit       => Dictionary.GetMainProgram);
      MemberOfExports := SeqAlgebra.FirstMember (TheHeap, PartitionExports);
      while not SeqAlgebra.IsNullMember (MemberOfExports) loop
         ExpVarRep := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                  M        => MemberOfExports);
         ExportVar := Dictionary.ConvertSymbolRef (ExaminerConstants.RefType (ExpVarRep));

         -- Do not process any dependency stuff associated with implicit exports of mode in
         if Dictionary.GetOwnVariableOrConstituentMode (ExportVar) /= Dictionary.InMode
           and then
           -- nor anything to do with exporting of the "data sink" null variable
           not Dictionary.Is_Null_Variable (ExportVar) then

            RelationAlgebra.ColExtraction
              (TheHeap,
               PartitionRho,
               SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                           M        => MemberOfExports),
               -- to get
               DependencyCol);

            RelationAlgebra.ColExtraction (TheHeap, ActualRho, ExpVarRep,
                                           -- to get
                                           RhoCol);

            MemberOfDependencyCol := SeqAlgebra.FirstMember (TheHeap, DependencyCol);
            -- If the spec says "derives Y from X" then there should be an entry in
            -- the Rho relation for this dependency. If not then flow error 50 is raised.
            -- This check is not performed in data-flow analysis mode.
            while CommandLineData.Content.Flow_Option /= CommandLineData.Data_Flow
              and then not SeqAlgebra.IsNullMember (MemberOfDependencyCol) loop
               DepRep := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                     M        => MemberOfDependencyCol);
               DepSym := Dictionary.ConvertSymbolRef (ExaminerConstants.RefType (DepRep));

               if not SeqAlgebra.IsMember (TheHeap, RhoCol, DepRep) then
                  FlowErrorsFound := True;
                  ErrorHandler.Dependency_Error
                    (Err_Type       => ErrorHandler.Not_Used,
                     Position       => EndPosition,
                     Import_Var_Sym => DepSym,
                     Export_Var_Sym => ExportVar,
                     Scope          => Scope);
               end if;
               MemberOfDependencyCol := SeqAlgebra.NextMember (TheHeap, MemberOfDependencyCol);
            end loop;

            MemberOfRhoCol := SeqAlgebra.FirstMember (TheHeap, RhoCol);
            while not SeqAlgebra.IsNullMember (MemberOfRhoCol) loop
               RhoRep := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                     M        => MemberOfRhoCol);
               RhoSym := Dictionary.ConvertSymbolRef (ExaminerConstants.RefType (RhoRep));
               --add guard to prevent dependencies on OUT streams being reported
               if not IsAnOutStream (RhoSym) then
                  if not SeqAlgebra.IsMember (TheHeap, DependencyCol, RhoRep) then
                     -- select which error message to use
                     if SeqAlgebra.IsMember (TheHeap, PartitionImports, RhoRep) then
                        FlowErrorsFound := True;
                        ErrorHandler.Dependency_Error
                          (Err_Type       => ErrorHandler.May_Be_Used,
                           Position       => EndPosition,
                           Import_Var_Sym => RhoSym,
                           Export_Var_Sym => ExportVar,
                           Scope          => Scope);
                     else -- not imported, so undefined
                        FlowErrorsFound := True;
                        ErrorHandler.Dependency_Error
                          (Err_Type       => ErrorHandler.Uninitialised,
                           Position       => EndPosition,
                           Import_Var_Sym => RhoSym,
                           Export_Var_Sym => ExportVar,
                           Scope          => Scope);
                     end if;
                     -- cfr1203 -- end if;
                  end if;
               end if;
               MemberOfRhoCol := SeqAlgebra.NextMember (TheHeap, MemberOfRhoCol);
            end loop;
            SeqAlgebra.DisposeOfSeq (TheHeap, DependencyCol);
            SeqAlgebra.DisposeOfSeq (TheHeap, RhoCol);
            -- cfr1203 -- end if;
         end if;
         MemberOfExports := SeqAlgebra.NextMember (TheHeap, MemberOfExports);
      end loop;
   end CompareRelations;

   ----------------------------------

   -- check that all actual imports/exports appear in aprtition somewhere
   procedure CheckUsages
   --# global in     ActualExports;
   --#        in     ActualImports;
   --#        in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     EndPosition;
   --#        in     LexTokenManager.State;
   --#        in     PartitionExports;
   --#        in     PartitionImports;
   --#        in out ErrorHandler.Error_Context;
   --#        in out FlowErrorsFound;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from ActualExports,
   --#                                         ActualImports,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         EndPosition,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         PartitionExports,
   --#                                         PartitionImports,
   --#                                         SPARK_IO.File_Sys,
   --#                                         TheHeap &
   --#         FlowErrorsFound            from *,
   --#                                         ActualExports,
   --#                                         ActualImports,
   --#                                         Dictionary.Dict,
   --#                                         PartitionExports,
   --#                                         PartitionImports,
   --#                                         TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap                    from *,
   --#                                         ActualExports,
   --#                                         ActualImports,
   --#                                         PartitionExports,
   --#                                         PartitionImports,
   --#                                         TheHeap;
   is
      Mem     : SeqAlgebra.MemberOfSeq;
      Sym     : Dictionary.Symbol;
      TempSeq : SeqAlgebra.Seq;

   begin -- CheckUsages

      -- Check that things claimed as Imports in partition Rho are actually imported somewhere
      SeqAlgebra.Complement (TheHeap, PartitionImports, ActualImports,
                             -- to get
                             TempSeq);
      Mem := SeqAlgebra.FirstMember (TheHeap, TempSeq);
      while not SeqAlgebra.IsNullMember (Mem) loop
         Sym :=
           Dictionary.ConvertSymbolRef (ExaminerConstants.RefType (SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                                                               M        => Mem)));
         if not Dictionary.Is_Null_Variable (Sym) then
            FlowErrorsFound := True;
            ErrorHandler.Usage_Error
              (Err_Type => ErrorHandler.Ineffective_Import,
               Position => EndPosition,
               Var_Sym  => Sym,
               Scope    => Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                                      The_Unit       => Dictionary.GetMainProgram));
         end if;
         Mem := SeqAlgebra.NextMember (TheHeap, Mem);
      end loop;
      SeqAlgebra.DisposeOfSeq (TheHeap, TempSeq);

      -- Check that things claimed as Exports in partition Rho are actually exported somewhere
      SeqAlgebra.Complement (TheHeap, PartitionExports, ActualExports,
                             -- to get
                             TempSeq);
      Mem := SeqAlgebra.FirstMember (TheHeap, TempSeq);
      while not SeqAlgebra.IsNullMember (Mem) loop
         Sym :=
           Dictionary.ConvertSymbolRef (ExaminerConstants.RefType (SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                                                               M        => Mem)));
         if not Dictionary.Is_Null_Variable (Sym)
           -- don't report updating of null
           -- following covers implicit updating of in streams that should not be reported
           and then (Dictionary.GetOwnVariableOrConstituentMode (Dictionary.GetMostEnclosingObject (Sym)) /= Dictionary.InMode)
         then
            FlowErrorsFound := True;
            ErrorHandler.Usage_Error
              (Err_Type => ErrorHandler.Undefined_Export,
               Position => EndPosition,
               Var_Sym  => Sym,
               Scope    => Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                                      The_Unit       => Dictionary.GetMainProgram));
         end if;
         Mem := SeqAlgebra.NextMember (TheHeap, Mem);
      end loop;
      SeqAlgebra.DisposeOfSeq (TheHeap, TempSeq);

      -- Check that things Actually Exported are also Exports of the partition Rho
      SeqAlgebra.Reduction (TheHeap, ActualExports, PartitionExports);
      -- anything left in ActualExports is exported but undefined (as far as partition anno is concerned)
      Mem := SeqAlgebra.FirstMember (TheHeap, ActualExports);
      while not SeqAlgebra.IsNullMember (Mem) loop
         Sym :=
           Dictionary.ConvertSymbolRef (ExaminerConstants.RefType (SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                                                               M        => Mem)));
         if Dictionary.GetOwnVariableOrConstituentMode (Dictionary.GetMostEnclosingObject (Sym)) /= Dictionary.InMode then
            FlowErrorsFound := True;
            ErrorHandler.Usage_Error
              (Err_Type => ErrorHandler.Updated_But_Not_In_Partition,
               Position => EndPosition,
               Var_Sym  => Sym,
               Scope    => Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                                      The_Unit       => Dictionary.GetMainProgram));
         end if;
         -- cfr1203 -- end if;
         Mem := SeqAlgebra.NextMember (TheHeap, Mem);
      end loop;

      -- Check that things Actually Imported are also Imports of the partition Rho
      SeqAlgebra.Reduction (TheHeap, ActualImports, PartitionImports);
      -- anything left in ActualImports is an ineffective import (as far as partition anno is concerned)
      Mem := SeqAlgebra.FirstMember (TheHeap, ActualImports);
      while not SeqAlgebra.IsNullMember (Mem) loop
         Sym :=
           Dictionary.ConvertSymbolRef (ExaminerConstants.RefType (SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                                                               M        => Mem)));
         if Dictionary.GetOwnVariableOrConstituentMode (Dictionary.GetMostEnclosingObject (Sym)) /= Dictionary.OutMode then
            FlowErrorsFound := True;
            ErrorHandler.Usage_Error
              (Err_Type => ErrorHandler.Referenced_But_Not_In_Partition,
               Position => EndPosition,
               Var_Sym  => Sym,
               Scope    => Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                                      The_Unit       => Dictionary.GetMainProgram));
         end if;
         -- cfr1203 -- end if;
         Mem := SeqAlgebra.NextMember (TheHeap, Mem);
      end loop;
   end CheckUsages;

begin -- FlowAnalysePartition
   Dependency_Node := Find_Derives_Node (Node => Node);
   -- ASSUME Dependency_Node = dependency_relation OR NULL
   --# check STree.Syntax_Node_Type (Dependency_Node, STree.Table) = SP_Symbols.dependency_relation or
   --#   Dependency_Node = STree.NullNode;
   if Dependency_Node = STree.NullNode then
      -- ASSUME Dependency_Node = NULL
      EndPosition := LexTokenManager.Null_Token_Position;
   else
      -- ASSUME Dependency_Node = dependency_relation
      EndPosition := STree.FindLastItemInDependencyRelation (Node => Dependency_Node);
   end if;
   BuildPartitionRho; -- this is the partition-wide dependency asserted by the partition annotation

   CalculateActualRho; -- sets SemErrorsFound

   if not SemErrorsFound then
      RelationAlgebra.CloseRelation (TheHeap, ActualRho); -- this is the closure of the union of all tasks and interrupts
      CompareRelations;
      CheckUsages;
   end if;

   RelationAlgebra.DisposeOfRelation (TheHeap, PartitionRho);
   RelationAlgebra.DisposeOfRelation (TheHeap, ActualRho);
   SeqAlgebra.DisposeOfSeq (TheHeap, PartitionExports);
   SeqAlgebra.DisposeOfSeq (TheHeap, PartitionImports);
   SeqAlgebra.DisposeOfSeq (TheHeap, ActualExports);
   SeqAlgebra.DisposeOfSeq (TheHeap, ActualImports);

   if not FlowErrorsFound
     and then not SemErrorsFound
     and then CommandLineData.Content.Flow_Option /= CommandLineData.Data_Flow then
      ErrorHandler.Report_Success
        (Position    => EndPosition,
         Subprog_Str => LexTokenManager.Main_Program_Token,
         Err_Num     => ErrorHandler.No_Error_Default);
   end if;

   -- If the main program does not WITH any tasks, then the only task is the environment task itself. In
   -- this case, the task must end with a plain loop.  It does not need to if there is at least on withed
   -- task since the endless loop in that task will be enough to prevent program termination.
   if not TaskFound then
      CheckLastStatementOfEnvironmentTaskIsPlainLoop;
   end if;

end FlowAnalysePartition;
