-------------------------------------------------------------------------------
-- (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.
--
--=============================================================================

with GNAT.Dynamic_Tables;
# if not SPARK then
pragma Warnings (Off);
# end if;
with GNAT.Table.Sort;
# if not SPARK then
pragma Warnings (On);
# end if;
with CommandLineData;
with ContextManager.Ops;
with E_Strings;
with ExaminerConstants;
with FileSystem;
with LexTokenLists;
with SLI.IO;
with SPARK_IO;
with SystemErrors;

--  Data structure of the cross-references table:
--
--  1. DECL_COMP_UNIT is an array of Decl_Comp_Unit_Item
--  (DECLARATION_COMPILATION_UNIT + SYM) where each
--  DECLARATION_COMPILATION_UNIT is a compilation unit (spec or body)
--  that the Examiner has performed a semantic analysis.
--
--  2. SYM is an array of Sym_Item (SYMBOL_DECLARATION +
--  USAGE_COMP_UNIT) where each SYMBOL_DECLARATION is a symbol that is
--  declared in the DECLARATION_COMPILATION_UNIT.
--
--  3. USAGE_COMP_UNIT is an array of Usage_Comp_Unit_Item
--  (USAGE_COMPILATION_UNIT + POS_REF_TYPE) where each
--  USAGE_COMPILATION_UNIT is a compilation unit (spec or body) where
--  the SYMBOL_DECLARATION declared in the
--  DECLARATION_COMPILATION_UNIT is used.
--
--  4. POS_REF_TYPE is an array of Pos_Ref_Type_Item (LINE_NUMBER +
--  COLUMN_NUMBER + REF_TYPE)
--
--  4.1 where each LINE_NUMBER is the line number where the
--  SYMBOL_DECLARATION declared in the DECLARATION_COMPILATION_UNIT
--  and used in the USAGE_COMP_UNIT is located,
--
--  4.2 where each COLUMN_NUMBER is the column number where the
--  SYMBOL_DECLARATION declared in the DECLARATION_COMPILATION_UNIT
--  and used in the USAGE_COMP_UNIT is located,
--
--  4.3 where each REF_TYPE is the type of crosse-reference of the
--  SYMBOL_DECLARATION declared in the DECLARATION_COMPILATION_UNIT
--  and used in the USAGE_COMP_UNIT.

--  * DECL_COMP_UNIT ------------------+-----------------------------------+----
--  | DECLARATION_COMPILATION_UNIT + 0 | DECLARATION_COMPILATION_UNIT_ITEM | ...
--  +--------------------------------+-+-----------------------------------+----
--                                   |
--                                   V
--                      * SYM --------------------+
--                      | SYMBOL_DECLARATION +    |  * USAGE_COMP_UNIT -----------+----------------------+----
--                      |            0------------+->| USAGE_COMPILATION_UNIT + 0 | USAGE_COMP_UNIT_ITEM | ...
--                      +-------------------------+  +--------------------------+-+----------------------+----
--                      | SYMBOL_DECLARATION_ITEM |                             |
--                      +-------------------------+                             V
--                      | ...                     |                   * POS_REF_TYPE -----+
--                                                                    | LINE_NUMBER +     |
--                                                                    | COLUMN_NUMBER +   |
--                                                                    | REF_TYPE          |
--                                                                    +-------------------+
--                                                                    | POS_REF_TYPE_ITEM |
--                                                                    +-------------------+
--                                                                    | ...               |

package body SLI.Xref
--# own State is Decl_Comp_Unit_P.Table;
is

   type SLI_Type_Char_Assoc_T is array (Dictionary.SLI_Type) of Character;

   SLI_Type_Char_Assoc : constant SLI_Type_Char_Assoc_T := SLI_Type_Char_Assoc_T'
     (Dictionary.SLI_Array_Object             => 'a',
      Dictionary.SLI_Array_Type               => 'A',
      Dictionary.SLI_Boolean_Object           => 'b',
      Dictionary.SLI_Boolean_Type             => 'B',
      Dictionary.SLI_Enumeration_Object       => 'e',
      Dictionary.SLI_Enumeration_Type         => 'E',
      Dictionary.SLI_Floating_Point_Object    => 'f',
      Dictionary.SLI_Floating_Point_Type      => 'F',
      Dictionary.SLI_Abstract_Type            => 'H',
      Dictionary.SLI_Signed_Integer_Object    => 'i',
      Dictionary.SLI_Signed_Integer_Type      => 'I',
      Dictionary.SLI_Generic_Package_Type     => 'k',
      Dictionary.SLI_Package_Type             => 'K',
      Dictionary.SLI_Label_On_Loop            => 'l',
      Dictionary.SLI_Modular_Integer_Object   => 'm',
      Dictionary.SLI_Modular_Integer_Type     => 'M',
      Dictionary.SLI_Enumeration_Literal      => 'n',
      Dictionary.SLI_Named_Number             => 'N',
      Dictionary.SLI_Fixed_Point_Object       => 'o',
      Dictionary.SLI_Fixed_Point_Type         => 'O',
      Dictionary.SLI_Record_Object            => 'r',
      Dictionary.SLI_Record_Type              => 'R',
      Dictionary.SLI_String_Object            => 's',
      Dictionary.SLI_String_Type              => 'S',
      Dictionary.SLI_Task_Object              => 't',
      Dictionary.SLI_Task_Type                => 'T',
      Dictionary.SLI_Generic_Procedure_Type   => 'u',
      Dictionary.SLI_Procedure_Type           => 'U',
      Dictionary.SLI_Generic_Function_Op      => 'v',
      Dictionary.SLI_Function_Op              => 'V',
      Dictionary.SLI_Protected_Object         => 'w',
      Dictionary.SLI_Protected_Type           => 'W',
      Dictionary.SLI_Entry_Family             => 'Y',
      Dictionary.SLI_Generic_Formal_Parameter => 'z',
      Dictionary.SLI_Unknown_Type             => 'Z');

   ----------------------------------------
   --  Pos_Ref_Type                      --
   ----------------------------------------
   type Pos_Ref_Type_Item_T is record
      Pos      : LexTokenManager.Token_Position;
      Ref_Type : Character;
   end record;

   type Pos_Ref_Type_Item_Index is range 0 .. Integer'Last;

# if not SPARK then
   package Pos_Ref_Type_P is new GNAT.Dynamic_Tables
     (Table_Component_Type => Pos_Ref_Type_Item_T,
      Table_Index_Type     => Pos_Ref_Type_Item_Index,
      Table_Low_Bound      => 1,
      Table_Initial        => 1024,
      Table_Increment      => 10);
# else
   --# inherit Xref;
   package Pos_Ref_Type_P
   is

      type Table_Ptr is array (Xref.Pos_Ref_Type_Item_Index) of Xref.Pos_Ref_Type_Item_T;

      type Instance is record
         Table : Table_Ptr;
      end record;

      procedure Init (T : out Instance);
      --# derives T from ;

      procedure Free (T : in Instance);
      --# derives null from T;

      procedure Append (T       : in out Instance;
                        New_Val : in     Xref.Pos_Ref_Type_Item_T);
      --# derives T from *,
      --#                New_Val;

   end Pos_Ref_Type_P;
# end if;

   ----------------------------------------
   --  Usage_Comp_Unit                   --
   ----------------------------------------
   type Usage_Comp_Unit_Item_T is record
      Usage_Comp_Unit : ContextManager.UnitDescriptors;
      Pos_Ref_Type    : Pos_Ref_Type_P.Instance;
      Sorted          : Boolean;
   end record;

   type Usage_Comp_Unit_Item_Index is range 0 .. ExaminerConstants.ContextManagerMaxUnits;

# if not SPARK then
   package Usage_Comp_Unit_P is new GNAT.Dynamic_Tables
     (Table_Component_Type => Usage_Comp_Unit_Item_T,
      Table_Index_Type     => Usage_Comp_Unit_Item_Index,
      Table_Low_Bound      => 1,
      Table_Initial        => 1024,
      Table_Increment      => 10);
# else
   --# inherit Xref;
   package Usage_Comp_Unit_P
   is

      type Table_Ptr is array (Xref.Usage_Comp_Unit_Item_Index) of Xref.Usage_Comp_Unit_Item_T;

      type Instance is record
         Table : Table_Ptr;
      end record;

      procedure Init (T : out Instance);
      --# derives T from ;

      procedure Free (T : in Instance);
      --# derives null from T;

      procedure Append (T       : in out Instance;
                        New_Val : in     Xref.Usage_Comp_Unit_Item_T);
      --# derives T from *,
      --#                New_Val;

   end Usage_Comp_Unit_P;
# end if;

   ----------------------------------------
   --  Sym                               --
   ----------------------------------------
   type Sym_Item_T is record
      Sym             : Dictionary.Symbol;
      Sym_Type        : Dictionary.SLI_Type;
      Usage_Comp_Unit : Usage_Comp_Unit_P.Instance;
   end record;

   type Sym_Item_Index is range 0 .. Natural'Last;

# if not SPARK then
   package Sym_P is new GNAT.Dynamic_Tables
     (Table_Component_Type => Sym_Item_T,
      Table_Index_Type     => Sym_Item_Index,
      Table_Low_Bound      => 1,
      Table_Initial        => 1024,
      Table_Increment      => 10);
# else
   --# inherit Xref;
   package Sym_P
   is

      type Table_Ptr is array (Xref.Sym_Item_Index) of Xref.Sym_Item_T;

      type Instance is record
         Table : Table_Ptr;
      end record;

      procedure Init (T : out Instance);
      --# derives T from ;

      procedure Free (T : in Instance);
      --# derives null from T;

      procedure Append (T       : in out Instance;
                        New_Val : in     Xref.Sym_Item_T);
      --# derives T from *,
      --#                New_Val;

   end Sym_P;
# end if;

   ----------------------------------------
   --  Decl_Comp_Unit                    --
   ----------------------------------------
   type Decl_Comp_Unit_Item_T is record
      Decl_Comp_Unit : ContextManager.UnitDescriptors;
      Nb_Separates   : Natural;
      Sym            : Sym_P.Instance;
   end record;

   type Decl_Comp_Unit_Item_Index is range 0 .. ExaminerConstants.ContextManagerMaxUnits;

# if not SPARK then
   package Decl_Comp_Unit_P is new GNAT.Table
     (Table_Component_Type => Decl_Comp_Unit_Item_T,
      Table_Index_Type     => Decl_Comp_Unit_Item_Index,
      Table_Low_Bound      => 1,
      Table_Initial        => 1024,
      Table_Increment      => 10);
   package Decl_Comp_Unit_Sort_P is new Decl_Comp_Unit_P.Sort;
# else
   --# inherit ContextManager,
   --#         Dictionary,
   --#         LexTokenManager,
   --#         Pos_Ref_Type_P,
   --#         Sym_P,
   --#         Usage_Comp_Unit_P,
   --#         Xref;
   package Decl_Comp_Unit_P
   --# own Table;
   --# initializes Table;
   is

      type Table_Ptr is array (Xref.Decl_Comp_Unit_Item_Index) of Xref.Decl_Comp_Unit_Item_T;

      Table : Table_Ptr := Table_Ptr'
        (others => Xref.Decl_Comp_Unit_Item_T'
           (Decl_Comp_Unit => ContextManager.NullUnit,
            Nb_Separates   => 0,
            Sym            => Sym_P.Instance'
              (Table => Sym_P.Table_Ptr'
                 (others => Xref.Sym_Item_T'
                    (Sym             => Dictionary.NullSymbol,
                     Sym_Type        => Dictionary.SLI_Unknown_Type,
                     Usage_Comp_Unit => Usage_Comp_Unit_P.Instance'
                       (Table => Usage_Comp_Unit_P.Table_Ptr'
                          (others => Xref.Usage_Comp_Unit_Item_T'
                             (Usage_Comp_Unit => ContextManager.NullUnit,
                              Pos_Ref_Type    => Pos_Ref_Type_P.Instance'
                                (Table => Pos_Ref_Type_P.Table_Ptr'
                                   (others => Xref.Pos_Ref_Type_Item_T'
                                      (Pos      => LexTokenManager.Null_Token_Position,
                                       Ref_Type => ' '))),
                              Sorted          => False))))))));

      procedure Init;
      --# global in out Table;
      --# derives Table from *;

      procedure Free;
      --# global in out Table;
      --# derives Table from *;

      procedure Append (New_Val : in Xref.Decl_Comp_Unit_Item_T);
      --# global in out Table;
      --# derives Table from *,
      --#                    New_Val;

   end Decl_Comp_Unit_P;
# end if;

   ----------------------------------------
   --  Pos_Ref_Type                      --
   ----------------------------------------
# if not SPARK then
   --  Sort Pos_Ref_Type table based on:
   --  1. the reference type of the usage
   --  2. the line number of the usage position
   --  3. the column number of the usage postion
   function Lt_Pos_Ref_Type (Comp1, Comp2 : Pos_Ref_Type_Item_T) return Boolean is
   begin
      if Comp1.Ref_Type < Comp2.Ref_Type then
         return True;
      elsif Comp1.Ref_Type > Comp2.Ref_Type then
         return False;
      elsif Integer (Comp1.Pos.Start_Line_No) < Integer (Comp2.Pos.Start_Line_No) then
         return True;
      elsif Integer (Comp1.Pos.Start_Line_No) > Integer (Comp2.Pos.Start_Line_No) then
         return False;
      else
         return Comp1.Pos.Start_Pos < Comp2.Pos.Start_Pos;
      end if;
   end Lt_Pos_Ref_Type;

   procedure Sort_Pos_Ref_Type_Table is new Pos_Ref_Type_P.Sort_Table (Lt => Lt_Pos_Ref_Type);

   function Pos_Ref_Type_Last (T : Pos_Ref_Type_P.Instance) return Pos_Ref_Type_Item_Index renames Pos_Ref_Type_P.Last;
# else
   package body Pos_Ref_Type_P is
   --# hide Pos_Ref_Type_P;
   end Pos_Ref_Type_P;

   procedure Sort_Pos_Ref_Type_Table (Table : in out Pos_Ref_Type_P.Instance)
   --# derives Table from *;
   is
   --# hide Sort_Pos_Ref_Type_Table;
   begin
      null;
   end Sort_Pos_Ref_Type_Table;

   function Pos_Ref_Type_Last (T : Pos_Ref_Type_P.Instance) return Pos_Ref_Type_Item_Index is
   --# hide Pos_Ref_Type_Last;
   begin
      null;
   end Pos_Ref_Type_Last;
# end if;

   ----------------------------------------
   --  Usage_Comp_Unit                   --
   ----------------------------------------
# if not SPARK then
   --  Sort Usage_Comp_Unit table based on the declaration line number
   --  in the SLI file.
   function Lt_Usage_Comp_Unit (Comp1, Comp2 : Usage_Comp_Unit_Item_T) return Boolean is
      Line_Number1 : Natural := 0;
      Line_Number2 : Natural := 0;
   begin
      if Comp1.Usage_Comp_Unit /= ContextManager.NullUnit then
         Line_Number1 := ContextManager.Ops.Get_Line_Number (Descriptor => Comp1.Usage_Comp_Unit);
      end if;
      if Comp2.Usage_Comp_Unit /= ContextManager.NullUnit then
         Line_Number2 := ContextManager.Ops.Get_Line_Number (Descriptor => Comp2.Usage_Comp_Unit);
      end if;
      return Line_Number1 < Line_Number2;
   end Lt_Usage_Comp_Unit;

   procedure Sort_Usage_Comp_Unit_Table is new Usage_Comp_Unit_P.Sort_Table (Lt => Lt_Usage_Comp_Unit);

   function Usage_Comp_Unit_Last (T : Usage_Comp_Unit_P.Instance) return Usage_Comp_Unit_Item_Index renames Usage_Comp_Unit_P.Last;
# else
   package body Usage_Comp_Unit_P is
   --# hide Usage_Comp_Unit_P;
   end Usage_Comp_Unit_P;

   procedure Sort_Usage_Comp_Unit_Table (Table : in out Usage_Comp_Unit_P.Instance)
   --# derives Table from *;
   is
   --# hide Sort_Usage_Comp_Unit_Table;
   begin
      null;
   end Sort_Usage_Comp_Unit_Table;

   function Usage_Comp_Unit_Last (T : Usage_Comp_Unit_P.Instance) return Usage_Comp_Unit_Item_Index is
   --# hide Usage_Comp_Unit_Last;
   begin
      null;
   end Usage_Comp_Unit_Last;
# end if;

   ----------------------------------------
   --  Sym                               --
   ----------------------------------------
# if not SPARK then
   --  Sort the Sym table based on
   --  1. the line number of the declaration position
   --  2. the column number of the declaration position
   function Lt_Sym (Comp1, Comp2 : Sym_Item_T) return Boolean is
      Pos1 : LexTokenManager.Token_Position := LexTokenManager.Null_Token_Position;
      Pos2 : LexTokenManager.Token_Position := LexTokenManager.Null_Token_Position;
   begin
      if not Dictionary.Is_Null_Symbol (Comp1.Sym) then
         Pos1 := Dictionary.Get_Symbol_Location (Item => Comp1.Sym);
      end if;
      if not Dictionary.Is_Null_Symbol (Comp2.Sym) then
         Pos2 := Dictionary.Get_Symbol_Location (Item => Comp2.Sym);
      end if;
      if Integer (Pos1.Start_Line_No) < Integer (Pos2.Start_Line_No) then
         return True;
      elsif Integer (Pos1.Start_Line_No) > Integer (Pos2.Start_Line_No) then
         return False;
      else
         return Pos1.Start_Pos < Pos2.Start_Pos;
      end if;
   end Lt_Sym;

   procedure Sort_Sym_Table is new Sym_P.Sort_Table (Lt => Lt_Sym);

   function Sym_Last (T : Sym_P.Instance) return Sym_Item_Index renames Sym_P.Last;
# else
   package body Sym_P is
   --# hide Sym_P;
   end Sym_P;

   procedure Sort_Sym_Table (Table : in out Sym_P.Instance)
   --# derives Table from *;
   is
   --# hide Sort_Sym_Table;
   begin
      null;
   end Sort_Sym_Table;

   function Sym_Last (T : Sym_P.Instance) return Sym_Item_Index is
   --# hide Sym_Last;
   begin
      null;
   end Sym_Last;
# end if;

   ----------------------------------------
   --  Decl_Comp_Unit                    --
   ----------------------------------------
# if not SPARK then
   --  Sort Decl_Comp_Unit table based on the declaration line number
   --  in the SLI file.
   function Lt_Decl_Comp_Unit (Comp1, Comp2 : Decl_Comp_Unit_Item_T) return Boolean is
      Line_Number1 : Natural := 0;
      Line_Number2 : Natural := 0;
   begin
      if Comp1.Decl_Comp_Unit /= ContextManager.NullUnit then
         Line_Number1 := ContextManager.Ops.Get_Line_Number (Descriptor => Comp1.Decl_Comp_Unit);
      end if;
      if Comp2.Decl_Comp_Unit /= ContextManager.NullUnit then
         Line_Number2 := ContextManager.Ops.Get_Line_Number (Descriptor => Comp2.Decl_Comp_Unit);
      end if;
      return Line_Number1 < Line_Number2;
   end Lt_Decl_Comp_Unit;

   procedure Sort_Decl_Comp_Unit_Table is new Decl_Comp_Unit_Sort_P.Sort_Table (Lt => Lt_Decl_Comp_Unit);

   function Decl_Comp_Unit_Last return Decl_Comp_Unit_Item_Index renames Decl_Comp_Unit_P.Last;
# else
   package body Decl_Comp_Unit_P is
   --# hide Decl_Comp_Unit_P;
   end Decl_Comp_Unit_P;

   procedure Sort_Decl_Comp_Unit_Table
   --# global in out Decl_Comp_Unit_P.Table;
   --# derives Decl_Comp_Unit_P.Table from *;
   is
   --# hide Sort_Decl_Comp_Unit_Table;
   begin
      null;
   end Sort_Decl_Comp_Unit_Table;

   function Decl_Comp_Unit_Last return Decl_Comp_Unit_Item_Index
   --# global in Decl_Comp_Unit_P.Table;
   is
   --# hide Decl_Comp_Unit_Last;
   begin
      null;
   end Decl_Comp_Unit_Last;
# end if;
   ----------------------------------------

   --  Search a compilation unit descriptor (Decl_Comp_Unit) in
   --  Decl_Comp_Unit_P.Table. Return the index number if found or 0
   --  if not found.
   function Search_Decl_Comp_Unit (Decl_Comp_Unit  : in ContextManager.UnitDescriptors) return Decl_Comp_Unit_Item_Index
   --# global in Decl_Comp_Unit_P.Table;
   is
      I        : Decl_Comp_Unit_Item_Index;
      Found    : Boolean;
      Top_Item : Decl_Comp_Unit_Item_Index;
   begin
      I        := 1;
      Found    := False;
      Top_Item := Decl_Comp_Unit_Last;
      while I <= Top_Item and then not Found loop
         if Decl_Comp_Unit_P.Table (I).Decl_Comp_Unit /= ContextManager.NullUnit
           and then Decl_Comp_Unit_P.Table (I).Decl_Comp_Unit = Decl_Comp_Unit then
            Found := True;
         else
            I := I + 1;
         end if;
      end loop;
      if not Found then
         I := 0;
      end if;
      return I;
   end Search_Decl_Comp_Unit;

   --  Search a symbol (Sym) in Decl_Comp_Unit_P.Table
   --  (Decl_Comp_Unit).Sym.Table. Return the index number if found or
   --  0 if not found.
   function Search_Sym (Decl_Comp_Unit  : in Decl_Comp_Unit_Item_Index;
                        Sym             : in Dictionary.Symbol) return Sym_Item_Index
   --# global in Decl_Comp_Unit_P.Table;
   is
      I        : Sym_Item_Index;
      Found    : Boolean;
      Top_Item : Sym_Item_Index;
   begin
      I        := 1;
      Found    := False;
      Top_Item := Sym_Last (T => Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym);
      while I <= Top_Item and then not Found loop
         if not Dictionary.Is_Null_Symbol (Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (I).Sym)
           and then Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (I).Sym = Sym then
            Found := True;
         else
            I := I + 1;
         end if;
      end loop;
      if not Found then
         I := 0;
      end if;
      return I;
   end Search_Sym;

   --  Search a compilation unit descriptor (Usage_Comp_Unit) in
   --  Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table
   --  (Sym).Usage_Comp_Unit.Table. Return the index number if found
   --  or 0 if not found.
   function Search_Usage_Comp_Unit (Decl_Comp_Unit   : in Decl_Comp_Unit_Item_Index;
                                    Sym              : in Sym_Item_Index;
                                    Usage_Comp_Unit  : in ContextManager.UnitDescriptors) return Usage_Comp_Unit_Item_Index
   --# global in Decl_Comp_Unit_P.Table;
   is
      I        : Usage_Comp_Unit_Item_Index;
      Found    : Boolean;
      Top_Item : Usage_Comp_Unit_Item_Index;
   begin
      I        := 1;
      Found    := False;
      Top_Item := Usage_Comp_Unit_Last (T => Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (Sym).Usage_Comp_Unit);
      while I <= Top_Item and then not Found loop
         if Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (Sym).Usage_Comp_Unit.Table (I).Usage_Comp_Unit /=
           ContextManager.NullUnit
           and then Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (Sym).Usage_Comp_Unit.Table (I).Usage_Comp_Unit = Usage_Comp_Unit then
            Found := True;
         else
            I := I + 1;
         end if;
      end loop;
      if not Found then
         I := 0;
      end if;
      return I;
   end Search_Usage_Comp_Unit;

   --  Search the position and reference type (Pos_Ref_Type) in
   --  Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table
   --  (Sym).Usage_Comp_Unit.Table
   --  (Usage_Comp_Unit).Pos_Ref_Type.Table. Return the index number
   --  if found or 0 if not found.
   function Search_Pos_Ref_Type (Decl_Comp_Unit  : in Decl_Comp_Unit_Item_Index;
                                 Sym             : in Sym_Item_Index;
                                 Usage_Comp_Unit : in Usage_Comp_Unit_Item_Index;
                                 Pos_Ref_Type    : in Pos_Ref_Type_Item_T) return Pos_Ref_Type_Item_Index
   --# global in Decl_Comp_Unit_P.Table;
   is
      I        : Pos_Ref_Type_Item_Index;
      Found    : Boolean;
      Top_Item : Pos_Ref_Type_Item_Index;
   begin
      I        := 1;
      Found    := False;
      Top_Item := Pos_Ref_Type_Last
        (T => Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (Sym).Usage_Comp_Unit.Table (Usage_Comp_Unit).Pos_Ref_Type);
      while I <= Top_Item and then not Found loop
         if Decl_Comp_Unit_P.Table
           (Decl_Comp_Unit).Sym.Table (Sym).Usage_Comp_Unit.Table (Usage_Comp_Unit).Pos_Ref_Type.Table (I) = Pos_Ref_Type then
            Found := True;
         else
            I := I + 1;
         end if;
      end loop;
      if not Found then
         I := 0;
      end if;
      return I;
   end Search_Pos_Ref_Type;

   procedure Increment_Nb_Separates (Comp_Unit  : in ContextManager.UnitDescriptors)
   --# global in out Decl_Comp_Unit_P.Table;
   --# derives Decl_Comp_Unit_P.Table from *,
   --#                                     Comp_Unit;
   is
      I                    : Decl_Comp_Unit_Item_Index;
      Decl_Comp_Unit_Item  : Decl_Comp_Unit_Item_T;
   begin
      --  Check if the compilation unit (Comp_Unit) has already been
      --  declared.
      I := Search_Decl_Comp_Unit (Decl_Comp_Unit => Comp_Unit);
      if I = 0 then
         --  Add the new compilation unit (Comp_Unit) in
         --  Decl_Comp_Unit_P.Table.
         Decl_Comp_Unit_Item.Decl_Comp_Unit := Comp_Unit;
         Decl_Comp_Unit_Item.Nb_Separates   := 0;
         Sym_P.Init (T => Decl_Comp_Unit_Item.Sym);
         Decl_Comp_Unit_P.Append (New_Val => Decl_Comp_Unit_Item);
         I := Decl_Comp_Unit_Last;
      end if;
      --# accept W, 169, Decl_Comp_Unit_P.Table, "Direct updates OK here";
      Decl_Comp_Unit_P.Table (I).Nb_Separates := Decl_Comp_Unit_P.Table (I).Nb_Separates + 1;
      --# end accept;
   exception
      --# hide Increment_Nb_Separates;
      when Storage_Error =>
         SystemErrors.Fatal_Error (Sys_Err => SystemErrors.XRef_Table_Full,
                                   Msg     => "SLI.XREF.INCREMENT_NB_SEPARATES : Cross-references table full");
   end Increment_Nb_Separates;

   procedure Add_Usage (Decl_Comp_Unit  : in ContextManager.UnitDescriptors;
                        Sym             : in Dictionary.Symbol;
                        Usage_Comp_Unit : in ContextManager.UnitDescriptors;
                        Pos             : in LexTokenManager.Token_Position;
                        Ref_Type        : in Character)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out Decl_Comp_Unit_P.Table;
   --#        in out SPARK_IO.File_Sys;
   --# derives Decl_Comp_Unit_P.Table from *,
   --#                                     Decl_Comp_Unit,
   --#                                     Dictionary.Dict,
   --#                                     Pos,
   --#                                     Ref_Type,
   --#                                     Sym,
   --#                                     Usage_Comp_Unit &
   --#         SPARK_IO.File_Sys      from *,
   --#                                     CommandLineData.Content,
   --#                                     Decl_Comp_Unit,
   --#                                     Decl_Comp_Unit_P.Table,
   --#                                     Dictionary.Dict,
   --#                                     LexTokenManager.State,
   --#                                     Sym,
   --#                                     Usage_Comp_Unit;
   is

      I                    : Decl_Comp_Unit_Item_Index;
      J                    : Sym_Item_Index;
      K                    : Usage_Comp_Unit_Item_Index;
      L                    : Pos_Ref_Type_Item_Index;
      Decl_Comp_Unit_Item  : Decl_Comp_Unit_Item_T;
      Sym_Item             : Sym_Item_T;
      Usage_Comp_Unit_Item : Usage_Comp_Unit_Item_T;
      Pos_Ref_Type_Item    : Pos_Ref_Type_Item_T;

   begin
      if Decl_Comp_Unit /= ContextManager.NullUnit
        and then not Dictionary.Is_Null_Symbol (Sym)
        and then Usage_Comp_Unit /= ContextManager.NullUnit then
         --  Check if the compilation unit (Decl_Comp_Unit) has
         --  already been declared.
         I := Search_Decl_Comp_Unit (Decl_Comp_Unit => Decl_Comp_Unit);
         if I = 0 then
            --  Add the new compilation unit (Decl_Comp_Unit) in
            --  Decl_Comp_Unit_P.Table.
            Decl_Comp_Unit_Item.Decl_Comp_Unit := Decl_Comp_Unit;
            Decl_Comp_Unit_Item.Nb_Separates   := 0;
            Sym_P.Init (T => Decl_Comp_Unit_Item.Sym);
            Decl_Comp_Unit_P.Append (New_Val => Decl_Comp_Unit_Item);
            I := Decl_Comp_Unit_Last;
         end if;
         --  Check if the symbol (Sym) has already been declared in
         --  the compilation unit (Decl_Comp_Unit).
         J := Search_Sym (Decl_Comp_Unit => I,
                          Sym            => Sym);
         if J = 0 then
            --  Add the new symbol (Sym) in Decl_Comp_Unit_P.Table
            --  (I).Sym.
            Sym_Item.Sym := Sym;
            Dictionary.Get_SLI_Type (Item   => Sym,
                                     Result => Sym_Item.Sym_Type);
            Usage_Comp_Unit_P.Init (T => Sym_Item.Usage_Comp_Unit);
            --# accept W, 169, Decl_Comp_Unit_P.Table, "Direct updates OK here";
            Sym_P.Append (T       => Decl_Comp_Unit_P.Table (I).Sym,
                          New_Val => Sym_Item);
            --# end accept;
            J := Sym_Last (T => Decl_Comp_Unit_P.Table (I).Sym);
         end if;
         --  Check if the compilation unit (Usage_Comp_Unit) has
         --  already been declared for the symbol (Sym) in the
         --  compilation unit (Decl_Comp_Unit).
         K := Search_Usage_Comp_Unit (Decl_Comp_Unit  => I,
                                      Sym             => J,
                                      Usage_Comp_Unit => Usage_Comp_Unit);
         if K = 0 then
            --  Add the new compilation unit (Usage_Comp_Unit) in
            --  Decl_Comp_Unit_P.Table (I).Sym.Table
            --  (J).Usage_Comp_Unit.
            Usage_Comp_Unit_Item.Usage_Comp_Unit := Usage_Comp_Unit;
            Usage_Comp_Unit_Item.Sorted          := False;
            Pos_Ref_Type_P.Init (T => Usage_Comp_Unit_Item.Pos_Ref_Type);
            --# accept W, 169, Decl_Comp_Unit_P.Table, "Direct updates OK here";
            Usage_Comp_Unit_P.Append (T       => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit,
                                      New_Val => Usage_Comp_Unit_Item);
            --# end accept;
            K := Usage_Comp_Unit_Last (T => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit);
         end if;
         --  Check if the new position and reference type
         --  (Pos_Ref_Type_Item) has already been declared for the
         --  compilation unit (Usage_Comp_Unit) in the symbol (Sym) in
         --  the compilation unit (Decl_Comp_Unit).
         Pos_Ref_Type_Item := Pos_Ref_Type_Item_T'(Pos      => Pos,
                                                   Ref_Type => Ref_Type);
         L := Search_Pos_Ref_Type (Decl_Comp_Unit  => I,
                                   Sym             => J,
                                   Usage_Comp_Unit => K,
                                   Pos_Ref_Type    => Pos_Ref_Type_Item);
         if L = 0 then
            --  Add the new position and reference type (Pos_Ref_Type)
            --  in Decl_Comp_Unit_P.Table (I).Sym.Table
            --  (J).Usage_Comp_Unit.Table (K).Pos_Ref_Type.

            --# accept W, 169, Decl_Comp_Unit_P.Table, "Direct updates OK here";
            Pos_Ref_Type_P.Append (T       => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Pos_Ref_Type,
                                   New_Val => Pos_Ref_Type_Item);
            --# end accept;
         end if;
      end if;
   exception
      --# hide Add_Usage;
      when Storage_Error =>
         SystemErrors.Fatal_Error (Sys_Err => SystemErrors.XRef_Table_Full,
                                   Msg     => "SLI.XREF.ADD_USAGE : Cross-references table full");
   end Add_Usage;

   --  Cleanup Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table
   --  (Sym).Usage_Comp_Unit.Table (Usage_Comp_Unit).Pos_Ref_Type.
   procedure Cleanup_Pos_Ref_Type (Decl_Comp_Unit  : in Decl_Comp_Unit_Item_Index;
                                   Sym             : in Sym_Item_Index;
                                   Usage_Comp_Unit : in Usage_Comp_Unit_Item_Index)
   --# global in out Decl_Comp_Unit_P.Table;
   --# derives Decl_Comp_Unit_P.Table from *,
   --#                                     Decl_Comp_Unit,
   --#                                     Sym,
   --#                                     Usage_Comp_Unit;
   is
   begin
      if Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (Sym).Usage_Comp_Unit.Table (Usage_Comp_Unit).Usage_Comp_Unit /=
        ContextManager.NullUnit then
         --# accept W, 169, Decl_Comp_Unit_P.Table, "Direct updates OK here";
         Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (Sym).Usage_Comp_Unit.Table (Usage_Comp_Unit).Usage_Comp_Unit :=
           ContextManager.NullUnit;
         --# end accept;
         Pos_Ref_Type_P.Free
           (T => Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (Sym).Usage_Comp_Unit.Table (Usage_Comp_Unit).Pos_Ref_Type);
         --# accept W, 169, Decl_Comp_Unit_P.Table, "Direct updates OK here";
         Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (Sym).Usage_Comp_Unit.Table (Usage_Comp_Unit).Sorted := False;
         --# end accept;
      end if;
   end Cleanup_Pos_Ref_Type;

   --  Cleanup Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table
   --  (Sym).Usage_Comp_Unit and all subtables.
   procedure Cleanup_Usage_Comp_Unit (Decl_Comp_Unit : in Decl_Comp_Unit_Item_Index;
                                      Sym            : in Sym_Item_Index)
   --# global in out Decl_Comp_Unit_P.Table;
   --# derives Decl_Comp_Unit_P.Table from *,
   --#                                     Decl_Comp_Unit,
   --#                                     Sym;
   is
      Top_Item : Usage_Comp_Unit_Item_Index;
      I        : Usage_Comp_Unit_Item_Index;
   begin
      if not Dictionary.Is_Null_Symbol (Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (Sym).Sym) then
         Top_Item := Usage_Comp_Unit_Last (T => Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (Sym).Usage_Comp_Unit);
         I        := 1;
         while I <= Top_Item loop
            Cleanup_Pos_Ref_Type (Decl_Comp_Unit  => Decl_Comp_Unit,
                                  Sym             => Sym,
                                  Usage_Comp_Unit => I);
            I := I + 1;
         end loop;
         --# accept W, 169, Decl_Comp_Unit_P.Table, "Direct updates OK here";
         Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (Sym).Sym := Dictionary.NullSymbol;
         --# end accept;
         Usage_Comp_Unit_P.Free (T => Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym.Table (Sym).Usage_Comp_Unit);
      end if;
   end Cleanup_Usage_Comp_Unit;

   --  Cleanup Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym and all
   --  subtables.
   procedure Cleanup_Sym (Decl_Comp_Unit : in Decl_Comp_Unit_Item_Index)
   --# global in out Decl_Comp_Unit_P.Table;
   --# derives Decl_Comp_Unit_P.Table from *,
   --#                                     Decl_Comp_Unit;
   is
      Top_Item : Sym_Item_Index;
      I        : Sym_Item_Index;
   begin
      if Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Decl_Comp_Unit /= ContextManager.NullUnit then
         Top_Item := Sym_Last (T => Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym);
         I        := 1;
         while I <= Top_Item loop
            Cleanup_Usage_Comp_Unit (Decl_Comp_Unit => Decl_Comp_Unit,
                                     Sym            => I);
            I := I + 1;
         end loop;
         --# accept W, 169, Decl_Comp_Unit_P.Table, "Direct updates OK here";
         Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Decl_Comp_Unit := ContextManager.NullUnit;
         Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Nb_Separates   := 0;
         --# end accept;
         Sym_P.Free (T => Decl_Comp_Unit_P.Table (Decl_Comp_Unit).Sym);
      end if;
   end Cleanup_Sym;

   --  Cleanup Decl_Comp_Unit_P.Table and all subtables.
   procedure Cleanup_Decl_Comp_Unit
   --# global in out Decl_Comp_Unit_P.Table;
   --# derives Decl_Comp_Unit_P.Table from *;
   is
      Top_Item : Decl_Comp_Unit_Item_Index;
      I        : Decl_Comp_Unit_Item_Index;
   begin
      Top_Item := Decl_Comp_Unit_Last;
      I        := 1;
      while I <= Top_Item loop
         Cleanup_Sym (Decl_Comp_Unit => I);
         I := I + 1;
      end loop;
      Decl_Comp_Unit_P.Free;
      Decl_Comp_Unit_P.Init;
   end Cleanup_Decl_Comp_Unit;

   procedure Dump (Comp_Unit : in ContextManager.UnitDescriptors)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.File_Heap;
   --#        in     ContextManager.Ops.Unit_Heap;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out Decl_Comp_Unit_P.Table;
   --#        in out SPARK_IO.File_Sys;
   --#           out IO.Stream_Buffer;
   --# derives Decl_Comp_Unit_P.Table from *,
   --#                                     Comp_Unit,
   --#                                     ContextManager.Ops.Unit_Heap,
   --#                                     Dictionary.Dict,
   --#                                     LexTokenManager.State &
   --#         IO.Stream_Buffer       from Comp_Unit,
   --#                                     ContextManager.Ops.File_Heap,
   --#                                     ContextManager.Ops.Unit_Heap,
   --#                                     Decl_Comp_Unit_P.Table,
   --#                                     Dictionary.Dict,
   --#                                     LexTokenManager.State &
   --#         SPARK_IO.File_Sys      from *,
   --#                                     CommandLineData.Content,
   --#                                     Comp_Unit,
   --#                                     ContextManager.Ops.Unit_Heap,
   --#                                     Decl_Comp_Unit_P.Table,
   --#                                     Dictionary.Dict,
   --#                                     LexTokenManager.State;
   is

      Top_Item_I           : Decl_Comp_Unit_Item_Index;
      Top_Item_J           : Sym_Item_Index;
      Top_Item_K           : Usage_Comp_Unit_Item_Index;
      I                    : Decl_Comp_Unit_Item_Index;
      J                    : Sym_Item_Index;
      K                    : Usage_Comp_Unit_Item_Index;
      Ref_Count            : Natural;
      Write_Decl_Comp_Unit : Boolean;
      Write_Sym            : Boolean;
      Unit_Name            : LexTokenLists.Lists;
      Dummy_Unit_Name      : LexTokenLists.Lists;
      Unit_Type            : ContextManager.UnitTypes;
      Dummy_Unit_Type      : ContextManager.UnitTypes;
      Current_Comp_Unit    : ContextManager.UnitDescriptors;
      Prev_Comp_Unit       : ContextManager.UnitDescriptors;
      Continue             : Boolean;

      --  This procedure dump and cleanup all the usages of the symbol
      --  (J) declared in the compilation unit (I) and used in the
      --  compilation unit (K).
      procedure Dump_Usage (Write_Usage_Comp_Unit : in     Boolean;
                            I                     : in     Decl_Comp_Unit_Item_Index;
                            J                     : in     Sym_Item_Index;
                            K                     : in     Usage_Comp_Unit_Item_Index;
                            Write_Decl_Comp_Unit  : in out Boolean;
                            Write_Sym             : in out Boolean;
                            Ref_Count             : in out Natural)
      --# global in     CommandLineData.Content;
      --#        in     ContextManager.Ops.File_Heap;
      --#        in     ContextManager.Ops.Unit_Heap;
      --#        in     Dictionary.Dict;
      --#        in     LexTokenManager.State;
      --#        in out Decl_Comp_Unit_P.Table;
      --#        in out SPARK_IO.File_Sys;
      --#           out IO.Stream_Buffer;
      --# derives Decl_Comp_Unit_P.Table from *,
      --#                                     ContextManager.Ops.Unit_Heap,
      --#                                     Dictionary.Dict,
      --#                                     I,
      --#                                     J,
      --#                                     K,
      --#                                     Write_Sym &
      --#         IO.Stream_Buffer       from ContextManager.Ops.File_Heap,
      --#                                     ContextManager.Ops.Unit_Heap,
      --#                                     Decl_Comp_Unit_P.Table,
      --#                                     Dictionary.Dict,
      --#                                     I,
      --#                                     J,
      --#                                     K,
      --#                                     LexTokenManager.State,
      --#                                     Ref_Count,
      --#                                     Write_Decl_Comp_Unit,
      --#                                     Write_Sym,
      --#                                     Write_Usage_Comp_Unit &
      --#         Ref_Count              from *,
      --#                                     Decl_Comp_Unit_P.Table,
      --#                                     Dictionary.Dict,
      --#                                     I,
      --#                                     J,
      --#                                     K,
      --#                                     Write_Sym &
      --#         SPARK_IO.File_Sys      from *,
      --#                                     CommandLineData.Content,
      --#                                     Decl_Comp_Unit_P.Table,
      --#                                     Dictionary.Dict,
      --#                                     I,
      --#                                     J,
      --#                                     LexTokenManager.State,
      --#                                     Write_Sym &
      --#         Write_Decl_Comp_Unit,
      --#         Write_Sym              from *;
      is
         Max_Ref_Count   : constant := 10;
         Str             : E_Strings.T;
         Pos             : LexTokenManager.Token_Position;
         Top_Item_L      : Pos_Ref_Type_Item_Index;
         L               : Pos_Ref_Type_Item_Index;
         Dummy_Unit_Name : LexTokenLists.Lists;
         Unit_Type       : ContextManager.UnitTypes;
         I_Cleanup       : Decl_Comp_Unit_Item_Index;
         Result          : Dictionary.SLI_Type;
      begin
         --  Write the name of the declaration compilation unit
         --  (I). Write it only once!
         if Write_Decl_Comp_Unit then
            IO.Put_String (Item => "X ");
            IO.Put_Integer (Item => ContextManager.Ops.Get_Line_Number (Descriptor => Decl_Comp_Unit_P.Table (I).Decl_Comp_Unit));
            IO.Put_Char (Item => ' ');
            Str := LexTokenManager.Lex_String_To_String
              (Lex_Str => ContextManager.Ops.GetSourceFileName
                 (Descriptor => ContextManager.Ops.Get_File_Descriptor
                    (Unit_Descriptor => Decl_Comp_Unit_P.Table (I).Decl_Comp_Unit)));
            IO.E_Strings_Put_String
              (E_Str => FileSystem.Just_File (Fn  => Str,
                                              Ext => True));
            IO.New_Line;
            Write_Decl_Comp_Unit := False;
         end if;

         --# assert True;

         --  Write the name of the symbol (J) declared in the
         --  compilation unit (I). Write it only once per declaration
         --  compilation unit (I)!
         if Write_Sym then
            Pos := Dictionary.Get_Symbol_Location (Item => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Sym);
            IO.Put_Integer (Item => Integer (Pos.Start_Line_No));
            if Decl_Comp_Unit_P.Table (I).Sym.Table (J).Sym_Type = Dictionary.SLI_Unknown_Type then
               --  The type was not yet known when the cross-reference
               --  has been added.
               Dictionary.Get_SLI_Type (Item   => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Sym,
                                        Result => Result);
               if Result = Dictionary.SLI_Unknown_Type then
                  --  At this point, the type must be known because we
                  --  are dumping the SLI file. If it is still
                  --  unknown, the symbol is assumed to be an abstract
                  --  type. It is the best that we can do here.
                  Result := Dictionary.SLI_Abstract_Type;
               end if;
               if CommandLineData.Content.Debug.SLI then
                  --  Debug
                  SPARK_IO.New_Line (File    => SPARK_IO.Standard_Output,
                                     Spacing => 1);
               end if;
               --# accept W, 169, Decl_Comp_Unit_P.Table, "Direct updates OK here";
               Decl_Comp_Unit_P.Table (I).Sym.Table (J).Sym_Type := Result;
               --# end accept;
            end if;
            IO.Put_Char (Item => SLI_Type_Char_Assoc (Decl_Comp_Unit_P.Table (I).Sym.Table (J).Sym_Type));
            IO.Put_Integer (Item => Pos.Start_Pos);
            IO.Put_Char (Item => ' ');
            Str := LexTokenManager.Lex_String_To_String
              (Lex_Str => Dictionary.GetSimpleName (Item => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Sym));
            IO.E_Strings_Put_String (E_Str => Str);
            Write_Sym := False;
         end if;

         --# assert True;

         --  Prevent to have very long lines of cross-references.
         if Ref_Count > Max_Ref_Count then
            IO.New_Line;
            IO.Put_Char (Item => '.');
            Ref_Count := 0;
         end if;

         IO.Put_Char (Item => ' ');

         --  Write the line number of the usage compilation unit
         --  (K). It is only needed if the declaration compilation
         --  unit (I) is different from the usage compilation unit
         --  (K).
         if Write_Usage_Comp_Unit
           and then Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Usage_Comp_Unit /= ContextManager.NullUnit then
            IO.Put_Integer
              (Item => ContextManager.Ops.Get_Line_Number
                 (Descriptor => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Usage_Comp_Unit));
            IO.Put_Char (Item => '|');
         end if;

         --# assert True;

         --  Dump all the usages of the symbol (J) declared in the
         --  compilation unit (I) and used in the compilation unit
         --  (K).
         Top_Item_L := Pos_Ref_Type_Last (T => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Pos_Ref_Type);
         L          := 1;

         --  Sort all the usages of the symbol (J) declared in the
         --  compilation unit (I) and used in the compilation unit
         --  (K). Optimisation : Sort the table only once.
         if Top_Item_L > 1
           and then not Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Sorted then
            --# accept W, 169, Decl_Comp_Unit_P.Table, "Direct updates OK here";
            Sort_Pos_Ref_Type_Table (Table => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Pos_Ref_Type);
            Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Sorted := True;
            --# end accept;
         end if;

         while L <= Top_Item_L loop
            --  Prevent to have very long lines of cross-references.
            if Ref_Count > Max_Ref_Count then
               IO.New_Line;
               IO.Put_Char (Item => '.');
               Ref_Count := 0;
            end if;
            if L /= 1 then
               IO.Put_Char (Item => ' ');
            end if;

            --  Dump the usage (L) of the symbol (J) declared in the
            --  compilation unit (I) and used in the compilation unit
            --  (K).
            IO.Put_Integer
              (Item => Integer
                 (Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Pos_Ref_Type.Table (L).Pos.Start_Line_No));
            IO.Put_Char
              (Item => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Pos_Ref_Type.Table (L).Ref_Type);
            IO.Put_Integer
              (Item => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Pos_Ref_Type.Table (L).Pos.Start_Pos);
            Ref_Count := Ref_Count + 1;
            L := L + 1;
         end loop;

         --# assert True;

         --  Cleanup all the usages of the symbol (J) declared in the
         --  compilation unit (I) and used in the compilation unit
         --  (K).
         if Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Usage_Comp_Unit /= ContextManager.NullUnit then
            --# accept F, 10, Dummy_Unit_Name, "Ineffective assignment here OK";
            ContextManager.Ops.GetUnitName
              (Descriptor => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Usage_Comp_Unit,
               UnitName   => Dummy_Unit_Name,
               UnitType   => Unit_Type);
            --# end accept;
            if Unit_Type = ContextManager.MainProgram
              or else Unit_Type = ContextManager.PackageBody
              or else Unit_Type = ContextManager.SubUnit then
               --  Never cleanup a specification.
               I_Cleanup := Search_Decl_Comp_Unit
                 (Decl_Comp_Unit => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Usage_Comp_Unit);

               --  Check if there are separates for this compilation
               --  unit. If there are no separates, we can cleanup the
               --  table of cross-references but if there are still
               --  separates, we need to keep the table of cross
               --  references until all the separates has been dumped.
               if I_Cleanup = 0 or else
                 (I_Cleanup /= 0 and then Decl_Comp_Unit_P.Table (I_Cleanup).Nb_Separates = 0) then
                  Cleanup_Pos_Ref_Type (Decl_Comp_Unit  => I,
                                        Sym             => J,
                                        Usage_Comp_Unit => K);
               end if;
            end if;
         end if;
         --# accept F, 33, Dummy_Unit_Name , "Dummy_Unit_Name not referenced here";
      end Dump_Usage;

   begin

      --  Optimisation : prepare the cleanup of the cross-references
      --  table. The goal of this preparation is to be able to cleanup
      --  the cross-references table just after dumping the
      --  cross-references info into the SLI file. This code
      --  calculates the field NB_SEPARATES as it will be after the
      --  dump of the compilation unit.
      --
      --  Start the calculation with the compilation unit for wich the
      --  dump is performed.
      Current_Comp_Unit := Comp_Unit;
      Continue := True;
      while Continue loop
         if Current_Comp_Unit /= ContextManager.NullUnit then
            --# accept F, 10, Dummy_Unit_Name, "Ineffective assignment here OK";
            ContextManager.Ops.GetUnitName (Descriptor => Current_Comp_Unit,
                                            UnitName   => Dummy_Unit_Name,
                                            UnitType   => Unit_Type);
            --# end accept;
            if Unit_Type = ContextManager.MainProgram
              or else Unit_Type = ContextManager.PackageBody
              or else Unit_Type = ContextManager.SubUnit then
               --  Never cleanup a specification.
               I := Search_Decl_Comp_Unit (Decl_Comp_Unit => Current_Comp_Unit);
               if I = 0 or else
                 (I /= 0 and then Decl_Comp_Unit_P.Table (I).Nb_Separates = 0) then
                  --  The current compilation unit doesn't have any
                  --  separates or all the separates has been dumped.
                  if Unit_Type = ContextManager.SubUnit then
                     --  The current compilation unit is a separate
                     --  that doesn't have any separates or that all
                     --  the separates has been dumped => CLEANUP the
                     --  cross-references for this seprate and get its
                     --  parent.
                     Prev_Comp_Unit := Current_Comp_Unit;
                     ContextManager.Ops.Get_Parent (Unit_Descriptor => Current_Comp_Unit);
                     --  The new current compilation unit becomes now
                     --  the parent of the previous current
                     --  compilation unit.
                     I := Search_Decl_Comp_Unit (Decl_Comp_Unit => Current_Comp_Unit);
                     if I /= 0 and then Decl_Comp_Unit_P.Table (I).Nb_Separates > 0 then
                        --  Decrement the number of separates of the
                        --  new current compilation unit (= the parent
                        --  of the previous current compilation unit).

                        --# accept W, 169, Decl_Comp_Unit_P.Table, "Direct updates OK here";
                        Decl_Comp_Unit_P.Table (I).Nb_Separates := Decl_Comp_Unit_P.Table (I).Nb_Separates - 1;
                        --# end accept;
                     else
                        --  The field NB_SEPARATES of the new current
                        --  compilation unit (= the parent of a
                        --  previous current compilation unit) must be
                        --  at least 1 => STOP.

                        --# accept F, 10, Dummy_Unit_Type, "Ineffective assignment here OK";
                        ContextManager.Ops.GetUnitName (Descriptor => Prev_Comp_Unit,
                                                        UnitName   => Unit_Name,
                                                        UnitType   => Dummy_Unit_Type);
                        --# end accept;
                        LexTokenLists.Print_List (File => SPARK_IO.Standard_Output,
                                                  List => Unit_Name);
                        SPARK_IO.New_Line (File    => SPARK_IO.Standard_Output,
                                           Spacing => 1);
                        if I /= 0 then
                           --# accept F, 10, Dummy_Unit_Type, "Ineffective assignment here OK";
                           ContextManager.Ops.GetUnitName (Descriptor => Current_Comp_Unit,
                                                           UnitName   => Unit_Name,
                                                           UnitType   => Dummy_Unit_Type);
                           --# end accept;
                           LexTokenLists.Print_List (File => SPARK_IO.Standard_Output,
                                                     List => Unit_Name);
                           SPARK_IO.New_Line (File    => SPARK_IO.Standard_Output,
                                              Spacing => 1);
                        end if;
                        Continue := False;
                        SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Other_Internal_Error,
                                                  Msg     => "SLI.XREF.DUMP PROGRAM ERROR");
                     end if;
                  else
                     --  The current compilation unit is not a
                     --  separate. The current compilation unit
                     --  doesn't have any separates or all the
                     --  separates has been dumped => CLEANUP the
                     --  cross-references for this body.
                     Continue := False;
                  end if;
               else
                  --  There are still separates for the current
                  --  compilation unit that need to be dumped => KEEP
                  --  the cross-references for this body.
                  Continue := False;
               end if;
            else
               --  The current compilation unit is a spec => KEEP the
               --  cross-references for this spec.
               Continue := False;
            end if;
         else
            --  The current compilation unit is null => STOP.
            Continue := False;
            SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Other_Internal_Error,
                                      Msg     => "SLI.XREF.DUMP PROGRAM ERROR");
         end if;
      end loop;

      IO.New_Line;

      --  Dump all the usages of all the symbols declared in all the
      --  compilation units and used in all compilation units. All the
      --  declaration compilation units and all the usage compilation
      --  units must be in the closure.
      Top_Item_I := Decl_Comp_Unit_Last;
      I          := 1;

      if Top_Item_I > 1 then
         Sort_Decl_Comp_Unit_Table;
      end if;

      while I <= Top_Item_I loop
         if Decl_Comp_Unit_P.Table (I).Decl_Comp_Unit /= ContextManager.NullUnit
           and then ContextManager.Ops.In_Closure (Descriptor => Decl_Comp_Unit_P.Table (I).Decl_Comp_Unit) then
            Write_Decl_Comp_Unit := True;

            --  Dump all the usages of all the symbols declared in the
            --  compilation unit (I) and used in all the compilation
            --  units. Declaration compilation unit (I) and all the
            --  usage compilation units must be in the closure.
            Top_Item_J := Sym_Last (T => Decl_Comp_Unit_P.Table (I).Sym);
            J          := 1;

            if Top_Item_J > 1 then
               --# accept W, 169, Decl_Comp_Unit_P.Table, "Direct updates OK here";
               Sort_Sym_Table (Table => Decl_Comp_Unit_P.Table (I).Sym);
               --# end accept;
            end if;

            while J <= Top_Item_J loop
               if not Dictionary.Is_Null_Symbol (Decl_Comp_Unit_P.Table (I).Sym.Table (J).Sym) then
                  Write_Sym := True;
                  Ref_Count := 2;

                  --  Dump all the usages of the symbol (J) declared
                  --  in the compilation unit (I) and used in all the
                  --  compilation units. Declaration compilation unit
                  --  (I) and all the usage compilation units must be
                  --  in the closure.

                  --  All the usages of the symbol (J) declared in the
                  --  compilation unit (I) and used in the compilation
                  --  unit where the symbol is declared must appears
                  --  at the beginning of the list of
                  --  cross-references.
                  K := Search_Usage_Comp_Unit (Decl_Comp_Unit  => I,
                                               Sym             => J,
                                               Usage_Comp_Unit => Decl_Comp_Unit_P.Table (I).Decl_Comp_Unit);
                  if K /= 0 then
                     --  Dump and cleanup all the usages of the symbol
                     --  (J) declared in the compilation unit (I) and
                     --  used in the compilation unit (K) with the
                     --  declaration compilation unit (I) the same as
                     --  the usage compilation unit (K). Declaration
                     --  compilation unit (I) must be in the closure.
                     Dump_Usage (Write_Usage_Comp_Unit => False,
                                 I                     => I,
                                 J                     => J,
                                 K                     => K,
                                 Write_Decl_Comp_Unit  => Write_Decl_Comp_Unit,
                                 Write_Sym             => Write_Sym,
                                 Ref_Count             => Ref_Count);
                  end if;

                  Top_Item_K := Usage_Comp_Unit_Last (T => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit);
                  K          := 1;

                  if Top_Item_K > 1 then
                     --# accept W, 169, Decl_Comp_Unit_P.Table, "Direct updates OK here";
                     Sort_Usage_Comp_Unit_Table (Table => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit);
                     --# end accept;
                  end if;

                  while K <= Top_Item_K loop
                     if Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Usage_Comp_Unit /=
                       ContextManager.NullUnit
                       and then Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Usage_Comp_Unit /=
                       Decl_Comp_Unit_P.Table (I).Decl_Comp_Unit
                       and then ContextManager.Ops.In_Closure
                       (Descriptor => Decl_Comp_Unit_P.Table (I).Sym.Table (J).Usage_Comp_Unit.Table (K).Usage_Comp_Unit) then
                        --  Dump and cleanup all the usages of the
                        --  symbol (J) declared in the compilation
                        --  unit (I) and used in the compilation unit
                        --  (K) with the declaration compilation unit
                        --  (I) different from the usage compilation
                        --  unit (K). Declaration compilation unit (I)
                        --  and usage compilation unit (K) must be in
                        --  the closure.
                        Dump_Usage (Write_Usage_Comp_Unit => True,
                                    I                     => I,
                                    J                     => J,
                                    K                     => K,
                                    Write_Decl_Comp_Unit  => Write_Decl_Comp_Unit,
                                    Write_Sym             => Write_Sym,
                                    Ref_Count             => Ref_Count);
                     end if;
                     K := K + 1;
                  end loop;
                  if not Write_Sym then
                     IO.New_Line;
                  end if;
                  J := J + 1;
               end if;
            end loop;

            --  Cleanup all the usages of all the symbols declared in
            --  the compilation unit (I) and used in all the
            --  compilation units.

            --# accept F, 10, Dummy_Unit_Name, "Ineffective assignment here OK";
            ContextManager.Ops.GetUnitName (Descriptor => Decl_Comp_Unit_P.Table (I).Decl_Comp_Unit,
                                            UnitName   => Dummy_Unit_Name,
                                            UnitType   => Unit_Type);
            --# end accept;
            if Unit_Type = ContextManager.MainProgram
              or else Unit_Type = ContextManager.PackageBody
              or else Unit_Type = ContextManager.SubUnit then
               --  Never cleanup a specification.
               if Decl_Comp_Unit_P.Table (I).Nb_Separates = 0 then
                  --  Check if there are separates for this
                  --  compilation unit. If there are no separates, we
                  --  can cleanup the table of cross-references but if
                  --  there are still separates, we need to keep the
                  --  table of cross references until all the
                  --  separates has been dumped.
                  Cleanup_Sym (Decl_Comp_Unit  => I);
               end if;
            end if;
         end if;
         I := I + 1;
      end loop;
      --# accept F, 33, Dummy_Unit_Name, "Dummy_Unit_Name not referenced here" &
      --#        F, 33, Dummy_Unit_Type, "Dummy_Unit_Type not referenced here";
   end Dump;

# if not SPARK then
begin
   Decl_Comp_Unit_P.Init;
# end if;
end SLI.Xref;
