home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / xref_tab.adb < prev    next >
Text File  |  1996-09-28  |  93KB  |  2,828 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT COMPILER COMPONENTS                         --
  4. --                                                                          --
  5. --                             X R E F _ T A B                              --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.109 $                             --
  10. --                                                                          --
  11. --           Copyright (c) 1992,1993,1994 NYU, All Rights Reserved          --
  12. --                                                                          --
  13. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  21. -- to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. --
  22. --                                                                          --
  23. ------------------------------------------------------------------------------
  24.  
  25. with Atree;   use Atree;
  26. with Csets;   use Csets;
  27. with Errout;  use Errout;
  28. with Gnatvsn;
  29. with Lib;     use Lib;
  30. with Namet;   use Namet;
  31. with Osint;   use Osint;
  32. with Sinfo;   use Sinfo;
  33. with Sinput;  use Sinput;
  34. with Stand;   use Stand;
  35.  
  36. package body Xref_Tab is
  37.  
  38.    Header_Full : constant String := "%%";
  39.    Header_Stub : constant String := "--";
  40.    --  String indicating if a file in a required unit (A file given in
  41.    --  argument to GNATF) or an auxiliary unit (A file loaded during
  42.    --  compilation)
  43.  
  44.    Line_Length : constant Natural := 79;
  45.    --  Where does this wierd value of 79 come from ???
  46.  
  47.    Entity_Indent : constant Integer :=  0;
  48.    --  Defines the indentation of lines containing declarations of entities.
  49.  
  50.    Reference_Indent : constant Integer :=  1;
  51.    --  Defines the indentation of lines containing the reference list to
  52.    --  an entity
  53.  
  54.    Indent : Integer;
  55.    --  Indentation of the current line depending on the line : entity
  56.    --  definition or reference list
  57.  
  58.    Too_Long_Indent : constant Integer :=  1;
  59.    --  These four constants should be transferred into types.ads ???
  60.    --  or possibly user parametrized in some way ???
  61.    --  Also, they should be documented ???
  62.    --  Used for the formatted output of Write_Buffer. Used how???
  63.  
  64.    Line_Too_Long : Boolean := False;
  65.    --  To signal a previous truncated line.
  66.    --  The indent then changes to be Too_Long_Indent spaces larger.
  67.  
  68.    Buffer : String (1 .. Line_Length + 1);
  69.    --  The buffer variable used to build formatted output (not NUL terminated)
  70.    --  Do we handle identifiers longer than this buffer properly???
  71.  
  72.    Buffer_Length : Natural := 0;
  73.    --  The current length of Buffer. Points to last character in Buffer
  74.  
  75.    -----------------------
  76.    -- Local Subprograms --
  77.    -----------------------
  78.  
  79.    procedure Add_Char_To_Buffer (The_Char : Character);
  80.    --  Appends the given Char to the end of Buffer. Used for calling
  81.    --  Unix_Write, which accepts text only in form of a Str.
  82.  
  83.    procedure Add_Nat_To_Buffer (Number : Nat);
  84.    --  Append given integer value to end of buffer
  85.  
  86.    procedure Add_Str_To_Buffer (Append : String);
  87.    --  Appends the given string to the end of Buffer.
  88.  
  89.    procedure Add_Tabs_To_Buffer;
  90.    --  Addsd tabulations between the nae of a file and its time stamp.
  91.  
  92.    function Scope_Path (The_Entity : Entity_Id) return String_Ptr;
  93.    --  Returns the path string of the given entity. A path string consists of
  94.    --  the name of the entity followed by the hierarchical scopes. The scope
  95.    --  entities are separated by a point. However the first separator changes
  96.    --  '#' if the entity is not accessible from outside the unit.
  97.  
  98.    procedure Write_Entity_Info (The_Entity : Entity_Acc);
  99.    --  Writes all the informations concerning the entity : path,
  100.    --  Place of declaration, Entity kind
  101.  
  102.    procedure Write_Path (The_Entity : Entity_Acc);
  103.    --  Places the path string of the given entity in Buffer.
  104.    --  A path string consists of the name of the entity followed
  105.    --  by the hierarchical scopes.
  106.  
  107.    procedure Write_Place_Of_Declaration (The_Entity : Entity_Acc);
  108.    --  Places the declaration string of the given entity in Buffer.
  109.    --  A declaration string consists of the file name in
  110.    --  which the entity is declared followed by the line number.
  111.  
  112.    procedure Write_Type (Text : String);
  113.    --  Places the Entity_Kind string of a given Entity_Kind'Image in Buffer.
  114.    --  The first two characters get cut ("E_");
  115.  
  116.    procedure Write_Unit_Info
  117.      (Header_Line  : String;
  118.       Current_Etbl : Entity_Table_Acc);
  119.    --  Writes the information line about the unit : Kind, Unit_Name, Status
  120.    --  and File_Name.
  121.  
  122.    ------------------------
  123.    -- Add_Char_To_Buffer --
  124.    ------------------------
  125.  
  126.    procedure Add_Char_To_Buffer (The_Char : Character) is
  127.    begin
  128.       if Buffer_Length = 0 then
  129.  
  130.          --  Do the correct indention.
  131.  
  132.          for J in 1 .. Indent loop
  133.             Buffer (J) := ' ';
  134.          end loop;
  135.  
  136.          Buffer_Length := Indent;
  137.  
  138.          --  Ignore a leading space.
  139.  
  140.          if The_Char /= ' ' then
  141.             Buffer (Buffer_Length + 1) := The_Char;
  142.             Buffer_Length := Buffer_Length + 1;
  143.          end if;
  144.  
  145.       elsif Buffer_Length + 1 > Line_Length then
  146.          if not Line_Too_Long then
  147.             Line_Too_Long := True;
  148.             Indent := Indent + Too_Long_Indent;
  149.          end if;
  150.  
  151.          Write_Xref_Info (Buffer (1 .. Buffer_Length));
  152.          Buffer_Length := 0;
  153.          Add_Char_To_Buffer (The_Char);
  154.  
  155.       else
  156.          Buffer (Buffer_Length + 1) := The_Char;
  157.          Buffer_Length := Buffer_Length + 1;
  158.  
  159.       end if;
  160.    end Add_Char_To_Buffer;
  161.  
  162.    -----------------------
  163.    -- Add_Nat_To_Buffer --
  164.    -----------------------
  165.  
  166.    procedure Add_Nat_To_Buffer (Number : Nat) is
  167.       Nat_Str : String (1 .. 10);
  168.       First   : Integer := Nat_Str'Last + 1;
  169.       Num     : Nat := Number;
  170.    begin
  171.       while Num >= 10 loop
  172.          First := First - 1;
  173.          Nat_Str (First) := Character'Val ((Num mod 10) + 48);
  174.          Num := Num / 10;
  175.       end loop;
  176.  
  177.       First := First - 1;
  178.       Nat_Str (First) := Character'Val ((Num mod 10) + 48);
  179.  
  180.       Add_Str_To_Buffer (Nat_Str (First .. Nat_Str'Last));
  181.  
  182.    end Add_Nat_To_Buffer;
  183.  
  184.    -----------------------
  185.    -- Add_Str_To_Buffer --
  186.    -----------------------
  187.  
  188.    procedure Add_Str_To_Buffer (Append : String) is
  189.    begin
  190.       if Buffer_Length = 0 then
  191.  
  192.          --  Do the correct indention.
  193.  
  194.          for J in 1 .. Indent loop
  195.             Buffer (J) := ' ';
  196.          end loop;
  197.  
  198.          Buffer_Length := Indent;
  199.       end if;
  200.  
  201.       if Buffer_Length + Append'Length <= Line_Length then
  202.  
  203.          --  All OK: no new line!
  204.  
  205.          Buffer (Buffer_Length + 1 .. Buffer_Length + Append'Length) :=
  206.             Append (Append'First .. Append'Last);
  207.          Buffer_Length := Buffer_Length + Append'Length;
  208.  
  209.       elsif Append'Length > Line_Length - Indent - Too_Long_Indent then
  210.  
  211.          --  New line and truncation of the string.
  212.  
  213.          if Buffer_Length > Indent then
  214.             Write_Xref_Info (Buffer (1 .. Buffer_Length));
  215.             Buffer_Length := 0;
  216.          end if;
  217.  
  218.          Add_Str_To_Buffer (Append
  219.            (Append'First .. Append'First + Line_Length - Indent - 1));
  220.          Write_Xref_Info (Buffer (1 .. Buffer_Length));
  221.          Buffer_Length := 0;
  222.  
  223.          if not Line_Too_Long then
  224.             Line_Too_Long := True;
  225.             Indent := Indent + Too_Long_Indent;
  226.             Add_Str_To_Buffer (Append
  227.               (Append'First + Line_Length - Indent + 1 .. Append'Last));
  228.          else
  229.             Add_Str_To_Buffer (Append
  230.               (Append'First + Line_Length - Indent .. Append'Last));
  231.          end if;
  232.  
  233.       else
  234.          --  Only new line!
  235.  
  236.          if not Line_Too_Long then
  237.             Line_Too_Long := True;
  238.             Indent := Indent + Too_Long_Indent;
  239.          end if;
  240.  
  241.          Write_Xref_Info (Buffer (1 .. Buffer_Length));
  242.          Buffer_Length := 0;
  243.          Add_Str_To_Buffer (Append);
  244.  
  245.       end if;
  246.    end Add_Str_To_Buffer;
  247.  
  248.    ------------------------
  249.    -- Add_Tabs_To_Buffer --
  250.    ------------------------
  251.  
  252.    procedure Add_Tabs_To_Buffer is
  253.       Tabs_Col : constant := 25;
  254.       Next_Tab : Natural := Buffer_Length + 1;
  255.  
  256.    begin
  257.       if Next_Tab > Tabs_Col then
  258.          Add_Char_To_Buffer (' ');
  259.       else
  260.          loop
  261.             Next_Tab := 8 * ((Next_Tab - 1) / 8) + 8 + 1;
  262.             exit when Next_Tab > Tabs_Col;
  263.             Add_Char_To_Buffer (Ascii.HT);
  264.          end loop;
  265.  
  266.          while Next_Tab < Tabs_Col loop
  267.             Add_Char_To_Buffer (' ');
  268.          end loop;
  269.       end if;
  270.  
  271.    end Add_Tabs_To_Buffer;
  272.  
  273.    procedure Write_Entity_Info (The_Entity : Entity_Acc) is
  274.  
  275.    begin
  276.       Indent := Entity_Indent;
  277.       Write_Path (The_Entity);
  278.  
  279.       if Entity_Info_In_Xref then
  280.          Write_Type (Entity_Kind'Image (The_Entity.Entity_Type));
  281.       end if;
  282.  
  283.       Write_Place_Of_Declaration (The_Entity);
  284.    end Write_Entity_Info;
  285.  
  286.    ----------------
  287.    -- Write_Path --
  288.    ----------------
  289.  
  290.    procedure Write_Path (The_Entity : Entity_Acc) is
  291.    begin
  292.       Add_Str_To_Buffer (The_Entity.Scope_Path.all);
  293.    end Write_Path;
  294.  
  295.    --------------------------------
  296.    -- Write_Place_Of_Declaration --
  297.    --------------------------------
  298.  
  299.    procedure Write_Place_Of_Declaration (The_Entity : Entity_Acc) is
  300.    begin
  301.       Add_Char_To_Buffer (' ');
  302.       Add_Nat_To_Buffer (Int (The_Entity.Line_Number));
  303.       Add_Char_To_Buffer (':');
  304.       Add_Nat_To_Buffer (Int (The_Entity.Col_Number));
  305.       Add_Char_To_Buffer (' ');
  306.  
  307.       if The_Entity.Real_Line /= No_Line_Number
  308.         and then The_Entity.Real_Col /= No_Column_Number
  309.       then
  310.          Add_Nat_To_Buffer (Int (The_Entity.Real_Line));
  311.          Add_Char_To_Buffer (':');
  312.          Add_Nat_To_Buffer (Int (The_Entity.Real_Col));
  313.          Add_Char_To_Buffer (' ');
  314.       end if;
  315.    end Write_Place_Of_Declaration;
  316.  
  317.    ----------------
  318.    -- Write_Type --
  319.    ----------------
  320.  
  321.    procedure Write_Type (Text : String) is
  322.       LC_Text : String := Text (Text'First + 2 .. Text'Last);
  323.    begin
  324.       Add_Char_To_Buffer (' ');
  325.  
  326.       for J in LC_Text'Range loop
  327.          LC_Text (J) :=  Fold_Lower (LC_Text (J));
  328.       end loop;
  329.  
  330.       Add_Str_To_Buffer (LC_Text);
  331.  
  332.    end Write_Type;
  333.  
  334.  
  335.    ---------------------
  336.    -- Write_Unit_Info --
  337.    ---------------------
  338.  
  339.    procedure Write_Unit_Info
  340.      (Header_Line  : String;
  341.       Current_Etbl : Entity_Table_Acc)
  342.    is
  343.    begin
  344.  
  345.       Indent := Entity_Indent;
  346.       Write_Xref_Info (Buffer (1 .. Buffer_Length));
  347.       Buffer_Length := 0;
  348.       Add_Str_To_Buffer (Header_Line);
  349.       Add_Char_To_Buffer (' ');
  350.       Add_Str_To_Buffer (Current_Etbl.File_Name.all);
  351.  
  352.       --  We write the time stamp of the file only if we ghenerate a single
  353.       --  xref file. In the other cases, file names and time stamps are written
  354.       --  at the beginning of the file
  355.  
  356.       if Global_Xref_File then
  357.          Add_Tabs_To_Buffer;
  358.          Add_Str_To_Buffer (Current_Etbl.Time_Stamp);
  359.          Add_Char_To_Buffer (' ');
  360.          Add_Str_To_Buffer (Header_Line);
  361.       end if;
  362.       Write_Xref_Info (Buffer (1 .. Buffer_Length));
  363.       Buffer_Length := 0;
  364.  
  365.    end Write_Unit_Info;
  366.  
  367.    ----------------
  368.    -- Add_Entity --
  369.    ----------------
  370.  
  371.    procedure Add_Entity
  372.      (To_Etbl     : in     Entity_Table_Acc;
  373.       Entity_Node : in     Entity_Id;
  374.       New_Entity  : in out Entity_Acc)
  375.    is
  376.       The_Kind     : constant Entity_Kind := Ekind (Entity_Node);
  377.       Parent_Node  : constant Node_Id     := Parent (Entity_Node);
  378.       Spec_Node    : Node_Id;
  379.  
  380.       Grand_Parent : Node_Id;
  381.       --  Bad name, as it is not always the grand parent, try to describe
  382.       --  it abstractly (i.e. what is it used for) rather than just saying
  383.       --  what it is ???
  384.  
  385.    begin
  386.       Namet.Get_Name_String (Chars (Entity_Node));
  387.  
  388.       New_Entity := new An_Entity;
  389.       --  new An_Entity reads very awkwardly, find a better name
  390.       --  for An_Entity ???
  391.  
  392.       New_Entity.Chars       := new String'(Name_Buffer (1 .. Name_Len));
  393.  
  394.       New_Entity.Entity_Node := Entity_Node;
  395.       New_Entity.Entity_Type := The_Kind;
  396.       New_Entity.Entity_Char := Chars (Entity_Node);
  397.       New_Entity.Entity_Sloc := Sloc (Entity_Node);
  398.  
  399.       if Include_Inlined
  400.         and then not All_Info_In_Xref
  401.         and then not To_Etbl.Has_Inlined
  402.         and then To_Etbl.Status in Spec_Status
  403.       then
  404.          if ((The_Kind = E_Procedure or else The_Kind = E_Function)
  405.                and then Is_Inlined (Entity_Node))
  406.            or else Nkind (Parent (Parent_Node)) in N_Generic_Declaration
  407.            or else Nkind (Parent_Node) in N_Generic_Renaming_Declaration
  408.          then
  409.             To_Etbl.Has_Inlined := True;
  410.          end if;
  411.       end if;
  412.  
  413.       New_Entity.Line_Number := Get_Line_Number (Sloc (Entity_Node));
  414.       New_Entity.Col_Number  := Get_Column_Number (Sloc (Entity_Node));
  415.  
  416.       if Nkind (Parent_Node) = N_Private_Type_Declaration
  417.         or else Nkind (Parent_Node) = N_Incomplete_Type_Declaration
  418.         or else (Nkind (Parent_Node) = N_Object_Declaration
  419.                   and then Constant_Present (Parent_Node)
  420.                   and then No (Expression (Parent_Node)))
  421.       then
  422.          declare
  423.             Full_View_Node : Entity_Id := Full_View (Entity_Node);
  424.  
  425.          begin
  426.             if Full_View_Node /= Empty then
  427.                New_Entity.Real_Line :=
  428.                  Get_Line_Number (Sloc (Full_View_Node));
  429.                New_Entity.Real_Col  :=
  430.                  Get_Column_Number (Sloc (Full_View_Node));
  431.             end if;
  432.          end;
  433.       end if;
  434.  
  435.       New_Entity.Scope_Path := Scope_Path (Entity_Node);
  436.  
  437.  
  438.       if Scope (Entity_Node) < Last_Standard_Node_Id
  439.         or else Nkind (Parent (Scope (Entity_Node))) = N_Package_Specification
  440.       then
  441.          New_Entity.Is_Direct := True;
  442.       end if;
  443.  
  444.       if (To_Etbl.Length = 0) then
  445.          To_Etbl.First_Entity := New_Entity;
  446.          To_Etbl.Last_Entity  := New_Entity;
  447.       else
  448.          To_Etbl.Last_Entity.Next_Entity := New_Entity;
  449.          To_Etbl.Last_Entity             := New_Entity;
  450.       end if;
  451.  
  452.       To_Etbl.Length := To_Etbl.Length + 1;
  453.  
  454.       --  We give no warnings if certain nodes have no references:
  455.       --
  456.       --  1. an enumeration literal
  457.       --  2. a record component
  458.       --  3. a package name in a package body or body stub
  459.       --  4. a subprogram name or its parameters in a subprogram body
  460.       --     or body stub which does not act as a spec.
  461.  
  462.       --  We do this because certain hidden references (e.g. within a
  463.       --  range construct or an aggregate) don't appear in our reference
  464.       --  list or because an identifier always points to the subprogram
  465.       --  name in the in the spec.
  466.  
  467.       if (The_Kind = E_Void
  468.           and then Nkind (Parent_Node) not in N_Generic_Instantiation)
  469.         or else The_Kind = E_Enumeration_Literal
  470.         or else Nkind (Parent_Node) = N_Component_Declaration
  471.         or else Nkind (Parent_Node) = N_Loop_Parameter_Specification
  472.         or else Nkind (Parent_Node) in N_Package_Body .. N_Task_Body
  473.         or else Nkind (Parent_Node) in N_Body_Stub
  474.         or else (The_Kind in Subprogram_Kind
  475.                   and then Nkind (Parent (Parent_Node)) = N_Subprogram_Body
  476.                   and then Corresponding_Spec (Parent (Parent_Node)) /= Empty)
  477.       then
  478.          New_Entity.Give_Warning := False;
  479.       end if;
  480.  
  481.       if The_Kind in Formal_Kind then
  482.  
  483.          --  We don't give warnings for parameters of Access Subprograms
  484.          --  or parameters of accept statement
  485.          --  But we guve warnings for Entry declaration
  486.  
  487.          Grand_Parent := Parent (Parent_Node);
  488.  
  489.          if Nkind (Parent (Grand_Parent)) = N_Subprogram_Declaration
  490.            or else Nkind (Grand_Parent) = N_Entry_Declaration
  491.            or else Nkind (Parent (Grand_Parent)) =
  492.                      N_Generic_Subprogram_Declaration
  493.          then
  494.             null;
  495.  
  496.          elsif (Nkind (Parent (Grand_Parent)) = N_Subprogram_Body
  497.                   and then
  498.                 Corresponding_Spec (Parent (Grand_Parent)) /= Empty)
  499.            or else Nkind (Parent (Grand_Parent)) = N_Subprogram_Body_Stub
  500.            or else Nkind (Grand_Parent) = N_Access_Function_Definition
  501.            or else Nkind (Grand_Parent) = N_Access_Procedure_Definition
  502.            or else Nkind (Grand_Parent) = N_Accept_Statement
  503.            or else (Nkind (Grand_Parent) = N_Entry_Body_Formal_Part
  504.                     and then Entry_Index_Specification (Grand_Parent) /=
  505.                                Empty)
  506.            or else (Nkind (Grand_Parent) /= N_Entry_Body_Formal_Part
  507.                       and then
  508.                     Is_Overloadable (Defining_Unit_Name (Grand_Parent))
  509.                       and then
  510.                     Is_Imported (Defining_Unit_Name (Grand_Parent)))
  511.          then
  512.             New_Entity.Give_Warning := False;
  513.          end if;
  514.  
  515.          --  These three lines need to be commented out becasue
  516.          --  they will always raise an Assertion_Failure exception
  517.          --  since Defining_Unit_Name returns a node whose Nkind
  518.          --  is N_Defining_Unit_Name whereas Einfo.Is_Internal
  519.          --  can only be applied to nodes whose Nkind is N_Entity ???
  520.  
  521.          --  if Einfo.Is_Internal (Defining_Unit_Name
  522.          --    (Grand_Parent)) then
  523.          --     New_Entity.Is_Internal := True;
  524.          --  end if;
  525.  
  526.       end if;
  527.  
  528.       --  When we are adding an entity which is defined in a subprogram body
  529.       --  we set the flag Is_Direct to True if this subprogrm is inlined
  530.       --  or a generic defined in the spec.
  531.  
  532.       if Include_Inlined and then not All_Info_In_Xref
  533.         and then (To_Etbl.Status = A_Body or else To_Etbl.Status = Sub_Body)
  534.       then
  535.  
  536.          if To_Etbl.Status = A_Body then
  537.             Spec_Node := Library_Unit (To_Etbl.Top_Node);
  538.          else
  539.             Spec_Node := Library_Unit (Library_Unit (To_Etbl.Top_Node));
  540.          end if;
  541.  
  542.          if Nkind (Unit (Spec_Node)) = N_Generic_Package_Declaration then
  543.             New_Entity.Is_Direct := True;
  544.  
  545.          elsif (Nkind (Parent (Parent_Node)) = N_Subprogram_Body
  546.             or else Nkind (Parent (Parent_Node)) = N_Subprogram_Declaration)
  547.          then
  548.             --  If the entity defined is a subprogram then we must check if
  549.             --  the definition appears in another subprogram.
  550.  
  551.             if Nkind (Parent_Node) = N_Function_Specification
  552.               or else Nkind (Parent_Node) = N_Procedure_Specification
  553.             then
  554.                Grand_Parent := Parent (Parent (Parent_Node));
  555.             else
  556.                Grand_Parent := Parent (Parent_Node);
  557.             end if;
  558.  
  559.             --  If the declaration appears in a subprogram, then we check if
  560.             --  this subprogram is is an inlimed or a generic.
  561.  
  562.             if Nkind (Grand_Parent) = N_Subprogram_Body
  563.               and then Corresponding_Spec (Grand_Parent) /= Empty
  564.               and then
  565.                 (Nkind (Parent (Parent (Corresponding_Spec (Grand_Parent)))) =
  566.                                      N_Generic_Subprogram_Declaration
  567.                   or else Is_Inlined (Corresponding_Spec (Grand_Parent)))
  568.  
  569.             then
  570.                --  We check that the inlined or generic subprogram appears
  571.                --  in a spec. We don't mind of inlined or generic subprograms
  572.                --  which are defined in bodies for example which aren't
  573.                --  exported.
  574.  
  575.                declare
  576.                   Spec_Node : Node_Id := Corresponding_Spec (Grand_Parent);
  577.  
  578.                begin
  579.                   if Nkind (Parent (Parent (Parent (Spec_Node)))) =
  580.                                               N_Package_Specification
  581.                   then
  582.                      New_Entity.Is_Direct := True;
  583.                   end if;
  584.                end;
  585.             end if;
  586.          end if;
  587.       end if;
  588.  
  589.    end Add_Entity;
  590.  
  591.    --------------
  592.    -- Add_Etbl --
  593.    --------------
  594.  
  595.    procedure Add_Etbl
  596.      (First_Etbl  : in out Entity_Table_Acc;
  597.       Last_Etbl   : in out Entity_Table_Acc;
  598.       Unit_Number : in     Unit_Number_Type;
  599.       New_Etbl    : in out Entity_Table_Acc)
  600.    is
  601.       Unit_Node    : Node_Id := Unit (Cunit (Unit_Number));
  602.  
  603.       Etbl_Tmp     : Entity_Table_Acc := First_Etbl;
  604.       --  To store the current entity table within the search loop.
  605.  
  606.       Found        : Boolean := False;
  607.  
  608.       Current_File : File_Name_Type :=
  609.                        Full_File_Name (Source_Index (Unit_Number));
  610.  
  611.    begin
  612.       --  We look if the entity table is already in the list.
  613.  
  614.       Namet.Get_Name_String (Current_File);
  615.  
  616.       while not Found loop
  617.  
  618.          if (Etbl_Tmp = null) then
  619.  
  620.             --  In this case we add the entity table to our list.
  621.  
  622.             New_Etbl := new Entity_Table;
  623.             New_Etbl.Unit_Number := Unit_Number;
  624.             New_Etbl.Next_Etbl := null;
  625.             New_Etbl.File_Name := new String'(Name_Buffer (1 .. Name_Len));
  626.             Namet.Get_Name_String (Unit_Name (Unit_Number));
  627.             New_Etbl.Unit_Name := new String'(Name_Buffer (1 .. Name_Len - 2));
  628.             New_Etbl.Time_Stamp := Source_File_Stamp (Current_File);
  629.  
  630.             if Name_Buffer (Name_Len) = 's' then
  631.                New_Etbl.Status := A_Spec;
  632.             elsif Acts_As_Spec (Cunit (Unit_Number)) then
  633.                New_Etbl.Status := Body_As_Spec;
  634.             else
  635.                New_Etbl.Status := A_Body;
  636.             end if;
  637.  
  638.             case Nkind (Unit_Node) is
  639.                when N_Subprogram_Declaration |  N_Subprogram_Body |
  640.                     N_Subprogram_Body_Stub =>
  641.                   Unit_Node := Specification (Unit_Node);
  642.  
  643.                   case Nkind (Unit_Node) is
  644.                      when N_Procedure_Specification =>
  645.                         New_Etbl.Kind := Proc;
  646.                      when N_Function_Specification =>
  647.                         New_Etbl.Kind := Func;
  648.                      when others =>
  649.                         New_Etbl.Kind := Unknown;
  650.                   end case;
  651.  
  652.                when N_Package_Declaration | N_Package_Instantiation |
  653.                     N_Package_Body        | N_Package_Body_Stub =>
  654.                   New_Etbl.Kind := Pack;
  655.  
  656.                when N_Generic_Declaration | N_Function_Instantiation |
  657.                     N_Procedure_Instantiation =>
  658.                   New_Etbl.Kind := Genr;
  659.  
  660.                when N_Task_Body_Stub =>
  661.                   New_Etbl.Kind := Tsk;
  662.  
  663.                when N_Subunit =>
  664.                   New_Etbl.Kind   := Subunit;
  665.                   New_Etbl.Status := Sub_Body;
  666.  
  667.                when others =>
  668.                   New_Etbl.Kind := Unknown;
  669.  
  670.             end case;
  671.  
  672.             New_Etbl.Top_Node := Cunit (Unit_Number);
  673.  
  674.             if (First_Etbl = null) then
  675.                First_Etbl := New_Etbl;
  676.                Last_Etbl  := New_Etbl;
  677.             else
  678.                Last_Etbl.Next_Etbl := New_Etbl;
  679.                Last_Etbl           := New_Etbl;
  680.             end if;
  681.  
  682.             Found := True;
  683.  
  684.          else
  685.             if (Etbl_Tmp.File_Name.all = Name_Buffer (1 .. Name_Len)) then
  686.  
  687.                --  In this case we update only the top Node_Id.
  688.  
  689.                Etbl_Tmp.Top_Node     := Cunit (Unit_Number);
  690.                Etbl_Tmp.Xref_Written := False;
  691.                Etbl_Tmp.Unit_Number  := Unit_Number;
  692.                New_Etbl := Etbl_Tmp;
  693.  
  694.                Found := True;
  695.  
  696.             else
  697.                Etbl_Tmp := Etbl_Tmp.Next_Etbl;
  698.             end if;
  699.  
  700.          end if;
  701.       end loop;
  702.  
  703.    end Add_Etbl;
  704.  
  705.  
  706.    -------------------
  707.    -- Add_Reference --
  708.    -------------------
  709.  
  710.    procedure Add_Reference
  711.      (To_Entity :  Entity_Acc;
  712.       New_Etbl  :  Entity_Table_Acc;
  713.       New_Ref   :  Node_Id)
  714.    is
  715.       R_Tmp    : Ref_Acc;
  716.  
  717.       New_Sloc : Source_Ptr := Sloc (New_Ref);
  718.  
  719.    begin
  720.       if To_Entity /= null then
  721.  
  722.          R_Tmp := new Ref;
  723.          R_Tmp.Ref_Node    := New_Ref;
  724.          R_Tmp.Sloc        := New_Sloc;
  725.  
  726.          if Nkind (New_Ref) /= N_Expanded_Name then
  727.             R_Tmp.Line_Number := Get_Line_Number (Sloc (New_Ref));
  728.             R_Tmp.Col_Number  := Get_Column_Number (Sloc (New_Ref));
  729.          else
  730.             R_Tmp.Line_Number :=
  731.               Get_Line_Number (Sloc (Selector_Name (New_Ref)));
  732.             R_Tmp.Col_Number :=
  733.               Get_Column_Number (Sloc (Selector_Name (New_Ref)));
  734.          end if;
  735.  
  736.          R_Tmp.Etbl        := New_Etbl;
  737.  
  738.          if To_Entity.First_Ref = null then
  739.             To_Entity.First_Ref := R_Tmp;
  740.             To_Entity.Last_Ref  := R_Tmp;
  741.          else
  742.             To_Entity.Last_Ref.Next_Ref := R_Tmp;
  743.             To_Entity.Last_Ref          := R_Tmp;
  744.          end if;
  745.  
  746.          if Nkind (Parent (New_Ref)) = N_Pragma_Argument_Association then
  747.             R_Tmp.Is_Pragma := True;
  748.  
  749.          else
  750.             To_Entity.Length := To_Entity.Length + 1;
  751.  
  752.             if Nkind (Parent (New_Ref)) = N_With_Clause then
  753.                if Elaborate_Present (Parent (New_Ref)) then
  754.                   R_Tmp.Is_An_Elaborated_With_Clause := True;
  755.                end if;
  756.             end if;
  757.          end if;
  758.  
  759.       end if;
  760.    end Add_Reference;
  761.  
  762.  
  763.    --------------
  764.    -- Add_With --
  765.    --------------
  766.  
  767.    procedure Add_With
  768.      (To_Etbl  : Entity_Table_Acc;
  769.       New_Etbl : Entity_Table_Acc;
  770.       Is_Implicit : Boolean := False)
  771.    is
  772.       W_Tmp : With_Acc := To_Etbl.First_With;
  773.       --  To store the current values within the search loop.
  774.  
  775.       Found  : Boolean  := False;
  776.  
  777.    begin
  778.       if W_Tmp = null then
  779.  
  780.          --  No With_Clause yet!
  781.  
  782.          To_Etbl.First_With             := new With_Clause;
  783.          To_Etbl.First_With.Withed_Etbl := New_Etbl;
  784.          To_Etbl.First_With.Is_Implicit := Is_Implicit;
  785.  
  786.          --  Set the field Prev_Msgs to Done to avoid that
  787.          --  the Xref checks if Implicit withed units are useful or not.
  788.          if Is_Implicit then
  789.             To_Etbl.First_With.Prev_Msgs := Done;
  790.          end if;
  791.       else
  792.          --  Look for New_Etbl, if not in the list creat a new With_Clause!
  793.  
  794.          if W_Tmp.Withed_Etbl = New_Etbl then
  795.             Found := True;
  796.          end if;
  797.  
  798.          while W_Tmp.Next_With /= null and then not Found loop
  799.             W_Tmp := W_Tmp.Next_With;
  800.  
  801.             if W_Tmp.Withed_Etbl = New_Etbl then
  802.                Found := True;
  803.             end if;
  804.          end loop;
  805.  
  806.          if not Found then
  807.             W_Tmp.Next_With             := new With_Clause;
  808.             W_Tmp.Next_With.Withed_Etbl := New_Etbl;
  809.             W_Tmp.Next_With.Is_Implicit := Is_Implicit;
  810.  
  811.             --  Set the field Prev_Msgs to Done to avoid that
  812.             --  the Xref checks if Implicit withed units are useful or not.
  813.             if Is_Implicit then
  814.                W_Tmp.Next_With.Prev_Msgs := Done;
  815.             end if;
  816.  
  817.          end if;
  818.  
  819.       end if;
  820.    end Add_With;
  821.  
  822.    --------------------------
  823.    -- Clear_And_Mark_Xrefs --
  824.    --------------------------
  825.  
  826.    procedure Clear_And_Mark_Xrefs
  827.      (Home_Etbl   : Entity_Table_Acc;
  828.       Target_Etbl : Entity_Table_Acc;
  829.       First_Pass  : Boolean;
  830.       In_Xref     : Boolean;
  831.       Count_Marks : Boolean := True)
  832.     is
  833.       E_Tmp                : Entity_Acc := Home_Etbl.First_Entity;
  834.       R_Tmp                : Ref_Acc;
  835.       Old_Marks            : Natural;
  836.       Is_Used_In_Elaborate : Boolean := False;
  837.       First_Reference      : Boolean := True;
  838.       Write_Unit           : Boolean := True;
  839.  
  840.       With_Clauses         : With_Acc;
  841.  
  842.    begin
  843.  
  844.       if Count_Marks then
  845.          Target_Etbl.Marked := False;
  846.       end if;
  847.  
  848.       while E_Tmp /= null loop
  849.  
  850.          if First_Pass and then Count_Marks then
  851.             E_Tmp.Marks := 0;
  852.          end if;
  853.  
  854.          First_Reference := True;
  855.  
  856.          Old_Marks := E_Tmp.Marks;
  857.          R_Tmp := E_Tmp.First_Ref;
  858.          Is_Used_In_Elaborate := False;
  859.  
  860.          while (R_Tmp /= null) loop
  861.  
  862.             if In_Xref and then not Home_Etbl.Xref_Written
  863.               and then R_Tmp.Etbl = Target_Etbl and then First_Pass then
  864.                if Xref_Flag
  865.                  and then not Global_Xref_File
  866.                  and then
  867.                    ((E_Tmp.Entity_Type not in Formal_Kind
  868.                              and then E_Tmp.Entity_Type /= E_Discriminant)
  869.                      or else All_Info_In_Xref)
  870.                then
  871.                   if Write_Unit then
  872.                      if Home_Etbl.RU then
  873.                         Write_Unit_Info (Header_Full, Home_Etbl);
  874.                      else
  875.                         Write_Unit_Info (Header_Stub, Home_Etbl);
  876.                      end if;
  877.  
  878.                      Write_Unit := False;
  879.                   end if;
  880.  
  881.  
  882.                   if First_Reference then
  883.  
  884.                      Write_Entity_Info (E_Tmp);
  885.  
  886.                      Write_Xref_Info (Buffer (1 .. Buffer_Length));
  887.                      Buffer_Length := 0;
  888.  
  889.                      Indent := Reference_Indent;
  890.  
  891.                      Add_Char_To_Buffer ('{');
  892.                      First_Reference := False;
  893.  
  894.                   else
  895.                      Indent := Reference_Indent;
  896.  
  897.                      Add_Char_To_Buffer (' ');
  898.                   end if;
  899.  
  900.                   Add_Nat_To_Buffer (Int (R_Tmp.Line_Number));
  901.                   Add_Char_To_Buffer (':');
  902.                   Add_Nat_To_Buffer (Int (R_Tmp.Col_Number));
  903.                end if;
  904.             end if;
  905.  
  906.             if R_Tmp.Etbl = Target_Etbl
  907.               and then not R_Tmp.Is_Pragma
  908.               and then (First_Pass or else not R_Tmp.Marked)
  909.               and then Count_Marks
  910.             then
  911.  
  912.                E_Tmp.Marks := E_Tmp.Marks + 1;
  913.                R_Tmp.Marked := True;
  914.  
  915.                if not Is_Used_In_Elaborate then
  916.                   Is_Used_In_Elaborate := R_Tmp.Is_An_Elaborated_With_Clause;
  917.                end if;
  918.  
  919.             else
  920.                if First_Pass and then Count_Marks then
  921.                   R_Tmp.Marked := False;
  922.                end if;
  923.             end if;
  924.  
  925.  
  926.             R_Tmp := R_Tmp.Next_Ref;
  927.          end loop;
  928.  
  929.          if Xref_Flag and then not First_Reference then
  930.             Add_Char_To_Buffer ('}');
  931.             Write_Xref_Info (Buffer (1 .. Buffer_Length));
  932.             Buffer_Length := 0;
  933.          end if;
  934.  
  935.          --  We mark the target entity table to signal that there are
  936.          --  some cross references found.
  937.  
  938.          --  We don't consider the first entity (always referenced in the
  939.          --  with clause) except if the target entity table is a subprogram,
  940.          --  (in this case we're only able to reference the first entity).
  941.  
  942.          if E_Tmp.Marks /= Old_Marks
  943.            and then not Target_Etbl.Marked
  944.          then
  945.             if E_Tmp /= Home_Etbl.First_Entity
  946.               or else Home_Etbl.Kind in Proc .. Genr
  947.                   --  Above explicit reference to range is improper ???
  948.                   --  Introduce proper subtype at point of declaration ???
  949.  
  950.               or else Is_Used_In_Elaborate
  951.             then
  952.                Target_Etbl.Marked := True;
  953.             end if;
  954.          end if;
  955.  
  956.          E_Tmp := E_Tmp.Next_Entity;
  957.       end loop;
  958.  
  959.       Home_Etbl.Xref_Written := True;
  960.  
  961.       --  Special treatment for Text_IO and Wide_Text_IO. Needed
  962.       --  because of the kludge used for nested generic packages.
  963.       --  See Rtsfind.Text_IO_Kludge for details.
  964.  
  965.       if not Target_Etbl.Marked
  966.         and then Home_Etbl.First_Entity /= null
  967.         and then
  968.           (Home_Etbl.First_Entity.Chars.all = "text_io"
  969.             or else
  970.            Home_Etbl.First_Entity.Chars.all = "wide_text_io")
  971.       then
  972.          With_Clauses := Target_Etbl.First_With;
  973.          while With_Clauses /= null loop
  974.             if With_Clauses.Is_Implicit then
  975.                Target_Etbl.Marked := True;
  976.                exit;
  977.             end if;
  978.  
  979.             With_Clauses := With_Clauses.Next_With;
  980.          end loop;
  981.       end if;
  982.  
  983.    end Clear_And_Mark_Xrefs;
  984.  
  985.    ------------------
  986.    -- Delete_Table --
  987.    ------------------
  988.  
  989.    procedure Delete_Table (Old_Etbl : Entity_Table_Acc) is
  990.    begin
  991.       null;
  992.    end Delete_Table;
  993.  
  994.    -----------------
  995.    -- Entity_Node --
  996.    -----------------
  997.  
  998.    function Entity_Node (The_Entity : Entity_Acc) return Entity_Id is
  999.    begin
  1000.       if The_Entity = null then
  1001.          return Empty;
  1002.       else
  1003.          return The_Entity.Entity_Node;
  1004.       end if;
  1005.    end Entity_Node;
  1006.  
  1007.    -----------------
  1008.    -- Entity_Type --
  1009.    -----------------
  1010.  
  1011.    function Entity_Type (The_Entity : Entity_Acc) return Entity_Kind is
  1012.    begin
  1013.       if The_Entity = null then
  1014.          return E_Void;
  1015.       else
  1016.          return The_Entity.Entity_Type;
  1017.       end if;
  1018.    end Entity_Type;
  1019.  
  1020.    -----------
  1021.    -- First --
  1022.    -----------
  1023.  
  1024.    function First (The_Etbl : Entity_Table_Acc) return Entity_Id is
  1025.    begin
  1026.       return The_Etbl.First_Entity.Entity_Node;
  1027.    end First;
  1028.  
  1029.    -----------
  1030.    -- First --
  1031.    -----------
  1032.  
  1033.    function First (The_Entity : Entity_Acc) return Ref_Acc is
  1034.    begin
  1035.       return The_Entity.First_Ref;
  1036.    end First;
  1037.  
  1038.    ------------------
  1039.    -- Give_Warning --
  1040.    ------------------
  1041.  
  1042.    function Give_Warning (The_Entity : Entity_Acc) return Boolean is
  1043.    begin
  1044.       return The_Entity.Give_Warning;
  1045.    end Give_Warning;
  1046.  
  1047.    ---------------
  1048.    -- In_E_List --
  1049.    ---------------
  1050.  
  1051.    function In_E_List
  1052.      (The_Etbl   : Entity_Table_Acc;
  1053.       The_Entity : Entity_Id)
  1054.       return       Entity_Acc
  1055.    is
  1056.       E_Tmp : Entity_Acc;
  1057.       --  To store the current entity within the search loop.
  1058.  
  1059.    begin
  1060.       E_Tmp := The_Etbl.First_Entity;
  1061.  
  1062.       while E_Tmp /= null
  1063.         and then E_Tmp.Entity_Node /= The_Entity
  1064.       loop
  1065.          E_Tmp := E_Tmp.Next_Entity;
  1066.       end loop;
  1067.  
  1068.       return E_Tmp;
  1069.    end In_E_List;
  1070.  
  1071.    -----------------
  1072.    -- In_Ref_List --
  1073.    -----------------
  1074.  
  1075.    function In_Ref_List
  1076.      (The_Entity : Entity_Acc;
  1077.       The_Ref    : Node_Id)
  1078.       return       Boolean
  1079.    is
  1080.       R_Tmp : Ref_Acc;
  1081.       --  To store the current reference within the search loop.
  1082.  
  1083.    begin
  1084.       if The_Entity = null then
  1085.          return False;
  1086.  
  1087.       else
  1088.          R_Tmp := The_Entity.First_Ref;
  1089.  
  1090.          while R_Tmp /= null
  1091.            and then R_Tmp.Ref_Node /= The_Ref loop
  1092.             R_Tmp := R_Tmp.Next_Ref;
  1093.          end loop;
  1094.  
  1095.          if R_Tmp = null then
  1096.             return False;
  1097.          else
  1098.             return True;
  1099.          end if;
  1100.  
  1101.       end if;
  1102.    end In_Ref_List;
  1103.  
  1104.    ------------------
  1105.    -- In_With_List --
  1106.    ------------------
  1107.  
  1108.    function In_With_List
  1109.      (Home_Etbl   : Entity_Table_Acc;
  1110.       Target_Etbl : Entity_Table_Acc)
  1111.       return        Boolean
  1112.    is
  1113.       W_Tmp : With_Acc;
  1114.       --  To store the current entity within the search loop.
  1115.  
  1116.    begin
  1117.       W_Tmp := Target_Etbl.First_With;
  1118.  
  1119.       while W_Tmp /= null
  1120.         and then W_Tmp.Withed_Etbl /= Home_Etbl
  1121.       loop
  1122.          W_Tmp := W_Tmp.Next_With;
  1123.       end loop;
  1124.  
  1125.       if W_Tmp = null then
  1126.          return False;
  1127.       else
  1128.          return True;
  1129.       end if;
  1130.  
  1131.    end In_With_List;
  1132.  
  1133.    -------------
  1134.    -- Is_Null --
  1135.    -------------
  1136.  
  1137.    function Is_Null (The_Entity : Entity_Acc) return Boolean is
  1138.    begin
  1139.       return The_Entity = null;
  1140.    end Is_Null;
  1141.  
  1142.    -------------
  1143.    -- Is_Null --
  1144.    -------------
  1145.  
  1146.    function Is_Null (The_Ref : Ref_Acc) return Boolean is
  1147.    begin
  1148.       return The_Ref = null;
  1149.    end Is_Null;
  1150.  
  1151.    ---------------
  1152.    -- Is_Pragma --
  1153.    ---------------
  1154.  
  1155.    function Is_Pragma (The_Ref : Ref_Acc) return Boolean is
  1156.    begin
  1157.       return The_Ref.Is_Pragma;
  1158.    end Is_Pragma;
  1159.  
  1160.    -----------------
  1161.    -- Mark_Entity --
  1162.    -----------------
  1163.  
  1164.    procedure Mark_Entity (Old_Entity : Entity_Acc) is
  1165.    begin
  1166.       if Old_Entity /= null then
  1167.          Old_Entity.Marks := Old_Entity.Marks + 1;
  1168.       end if;
  1169.    end Mark_Entity;
  1170.  
  1171.    --------------------------
  1172.    -- Mark_Withed_Entities --
  1173.    --------------------------
  1174.  
  1175.    procedure Mark_Withed_Entities (The_Etbl : Entity_Table_Acc) is
  1176.       R : Ref_Acc := The_Etbl.First_Entity.First_Ref;
  1177.  
  1178.       Current_Etbl  : Entity_Table_Acc;
  1179.       Previous_Etbl : Entity_Table_Acc;
  1180.  
  1181.       First : Boolean := True;
  1182.       --  To suppress multiple calls of Mark_Xrefs for the same client.
  1183.  
  1184.    begin
  1185.       --  We loop through all the references of the unit name entity.
  1186.       --  Each client must have at least one such reference in
  1187.       --  this list (the one of the with clause).
  1188.  
  1189.       while (R /= null) loop
  1190.  
  1191.          Current_Etbl := R.Etbl;
  1192.  
  1193.          if Current_Etbl /= Previous_Etbl
  1194.            and then Current_Etbl /= The_Etbl
  1195.            and then Current_Etbl.RU
  1196.          then
  1197.             --  If we find a cross reference of a new entity table then
  1198.             --  we mark the referenced entities.
  1199.  
  1200.             Clear_And_Mark_Xrefs (The_Etbl, Current_Etbl, First, False);
  1201.             First := False;
  1202.             Previous_Etbl := Current_Etbl;
  1203.          end if;
  1204.  
  1205.          R := R.Next_Ref;
  1206.       end loop;
  1207.  
  1208.    end Mark_Withed_Entities;
  1209.  
  1210.    ----------
  1211.    -- Next --
  1212.    ----------
  1213.  
  1214.    function Next (The_Entity : Entity_Acc) return Entity_Acc is
  1215.    begin
  1216.       if The_Entity = null then
  1217.          return null;
  1218.       else
  1219.          return The_Entity.Next_Entity;
  1220.       end if;
  1221.    end Next;
  1222.  
  1223.    ----------
  1224.    -- Next --
  1225.    ----------
  1226.  
  1227.    function Next (The_Ref : Ref_Acc) return Ref_Acc is
  1228.    begin
  1229.       if The_Ref = null then
  1230.          return null;
  1231.       else
  1232.          return The_Ref.Next_Ref;
  1233.       end if;
  1234.    end Next;
  1235.  
  1236.    ---------------------
  1237.    -- Number_Of_Marks --
  1238.    ---------------------
  1239.  
  1240.    function Number_Of_Marks (The_Entity : Entity_Acc) return Natural is
  1241.    begin
  1242.       if The_Entity = null then
  1243.          return 0;
  1244.       else
  1245.          return The_Entity.Marks;
  1246.       end if;
  1247.    end Number_Of_Marks;
  1248.  
  1249.    --------------------
  1250.    -- Number_Of_Refs --
  1251.    --------------------
  1252.  
  1253.    function Number_Of_Refs (The_Entity : Entity_Acc) return Natural is
  1254.    begin
  1255.       if The_Entity = null then
  1256.          return 0;
  1257.       else
  1258.          return The_Entity.Length;
  1259.       end if;
  1260.    end Number_Of_Refs;
  1261.  
  1262.    ----------------
  1263.    -- Scope_Path --
  1264.    ----------------
  1265.  
  1266.    function Scope_Path (The_Entity : Entity_Id) return String_Ptr is
  1267.       Scope_Node : Node_Id;
  1268.  
  1269.       Max_Buffer_Length : constant Natural := 100;
  1270.       --  The length of Buffer is limited to 100 characters.
  1271.  
  1272.       Buffer : String (1 .. Max_Buffer_Length);
  1273.       --  The buffer variable to enable formatted output.
  1274.       --  The string in Buffer is *not* NUL terminated!
  1275.       --
  1276.       --  Note: We fill the Buffer from the right to the left.
  1277.       --        So we can do with iteration instead of recursion.
  1278.  
  1279.       Buffer_Entry : Positive := Max_Buffer_Length;
  1280.       --  The current entry into Buffer (points to the last empty field).
  1281.  
  1282.       Loop_String  : constant String (1 .. 4) := "loop";
  1283.       Block_String : constant String (1 .. 5) := "block";
  1284.  
  1285.       procedure Insert_Char_In_Buffer (The_Char : Character);
  1286.       --  Insert one character in buffer if it fits, otherwise ignore call
  1287.  
  1288.       procedure Insert_Str_In_Buffer (Insert : String);
  1289.       --  Insert given string in buffer (does nothing if string is too long)
  1290.  
  1291.       procedure Insert_Char_In_Buffer (The_Char : Character) is
  1292.       begin
  1293.          if Buffer_Entry = 0 then
  1294.             null;
  1295.          else
  1296.             Buffer (Buffer_Entry) := The_Char;
  1297.             Buffer_Entry := Buffer_Entry - 1;
  1298.          end if;
  1299.       end Insert_Char_In_Buffer;
  1300.  
  1301.       procedure Insert_Str_In_Buffer (Insert : String) is
  1302.       begin
  1303.          if Insert'Length > Buffer_Entry then
  1304.             null;
  1305.          else
  1306.             Buffer (Buffer_Entry - Insert'Length + 1 .. Buffer_Entry) :=
  1307.               Insert (1 .. Insert'Length);
  1308.             Buffer_Entry := Buffer_Entry - Insert'Length;
  1309.          end if;
  1310.       end Insert_Str_In_Buffer;
  1311.  
  1312.    --  Start of processing for Scope_Path
  1313.  
  1314.    begin
  1315.       --  Insert_Char_In_Buffer ('/');
  1316.  
  1317.       --  If the entity is visible from outside we add a # to its scope.
  1318.       --  Thus we can easily distinguish between entities declared within
  1319.       --  the body and those declared within the spec.
  1320.  
  1321.       Scope_Node := The_Entity;
  1322.       Namet.Get_Decoded_Name_String (Chars (Scope_Node));
  1323.       Insert_Str_In_Buffer (Name_Buffer (1 .. Name_Len));
  1324.       Scope_Node := Scope (Scope_Node);
  1325.  
  1326.       if Scope_Node < Last_Standard_Node_Id then
  1327.          return new String'(Buffer (Buffer_Entry + 1 .. Max_Buffer_Length));
  1328.       end if;
  1329.  
  1330.       --  We stop adding scopes if we find a scope which is declared within
  1331.       --  the Standard package.
  1332.  
  1333.       while Scope (Scope_Node) > Last_Standard_Node_Id loop
  1334.  
  1335.          Insert_Char_In_Buffer ('.');
  1336.  
  1337.          Namet.Get_Name_String (Chars (Scope_Node));
  1338.  
  1339.          --  Following code knows far too much about encoding of names ???
  1340.          --  Probably so, since names are no longer of the form listed below???
  1341.  
  1342.          if Ekind (Scope_Node) = E_Loop
  1343.            and then not Comes_From_Source (Scope_Node)
  1344.          then
  1345.             --  Given 'loop__456' we suppress the '__456'.
  1346.             --  This is very suspicious, Xref knows too much here ???
  1347.  
  1348.             Insert_Str_In_Buffer (Loop_String);
  1349.  
  1350.          elsif Ekind (Scope_Node) = E_Block
  1351.            and then not Comes_From_Source (Scope_Node)
  1352.          then
  1353.             --  Given 'block__1002' we suppress the '__1002'.
  1354.             --  This is very suspicious, Xref knows too much here ???
  1355.  
  1356.             Insert_Str_In_Buffer (Block_String);
  1357.  
  1358.          else
  1359.             Insert_Str_In_Buffer (Name_Buffer (1 .. Name_Len));
  1360.          end if;
  1361.  
  1362.          Scope_Node := Scope (Scope_Node);
  1363.       end loop;
  1364.  
  1365.       return new String'(Buffer (Buffer_Entry + 1 .. Max_Buffer_Length));
  1366.  
  1367.    end Scope_Path;
  1368.  
  1369.    --------------
  1370.    -- The_Node --
  1371.    --------------
  1372.  
  1373.    function The_Node (The_Ref : Ref_Acc) return Node_Id is
  1374.    begin
  1375.       return The_Ref.Ref_Node;
  1376.    end The_Node;
  1377.  
  1378.    --------------------
  1379.    -- Unmark_Entity  --
  1380.    --------------------
  1381.  
  1382.    procedure Unmark_Entity
  1383.      (The_Table  : Entity_Table_Acc;
  1384.       Old_Entity : Entity_Acc)
  1385.    is
  1386.    begin
  1387.       if The_Table /= null
  1388.         and then Old_Entity /= null
  1389.       then
  1390.          Old_Entity.Marks := 0;
  1391.       end if;
  1392.    end Unmark_Entity;
  1393.  
  1394.    ----------------------
  1395.    -- Unmark_Reference --
  1396.    ----------------------
  1397.  
  1398.    procedure Unmark_Reference
  1399.      (The_Entity : Entity_Acc;
  1400.       Old_Ref    : Node_Id)
  1401.    is
  1402.       R_Tmp : Ref_Acc;
  1403.       --  To store the current references within the search loop.
  1404.  
  1405.    begin
  1406.       if The_Entity /= null then
  1407.  
  1408.          --  First we search the fitting reference,
  1409.  
  1410.          R_Tmp := The_Entity.First_Ref;
  1411.  
  1412.          while R_Tmp /= null
  1413.            and then R_Tmp.Ref_Node /= Old_Ref
  1414.          loop
  1415.             R_Tmp := R_Tmp.Next_Ref;
  1416.          end loop;
  1417.  
  1418.          --  Then we unmark it.
  1419.  
  1420.          if R_Tmp /= null and then R_Tmp.Marked = True then
  1421.             R_Tmp.Marked := False;
  1422.             The_Entity.Marks  := The_Entity.Marks - 1;
  1423.          end if;
  1424.  
  1425.       end if;
  1426.    end Unmark_Reference;
  1427.  
  1428.    -------------------
  1429.    -- Update_Entity --
  1430.    -------------------
  1431.  
  1432.    procedure Update_Entity
  1433.      (To_Etbl     : in     Entity_Table_Acc;
  1434.       Entity_Node : in     Entity_Id;
  1435.       New_Entity  : in out Entity_Acc)
  1436.    is
  1437.       New_Sloc : Source_Ptr;
  1438.       Found    : Boolean := False;
  1439.       Path_Ptr : String_Ptr;
  1440.  
  1441.    begin
  1442.       New_Entity := To_Etbl.First_Entity;
  1443.       New_Sloc   := Sloc (Entity_Node);
  1444.  
  1445.  
  1446.       --  In the case of generics we have to compare the whole
  1447.       --  path string since we have lots of entities with same
  1448.       --  line numbers and chars.
  1449.  
  1450.       if To_Etbl.Kind = Genr then
  1451.          Path_Ptr := Scope_Path (Entity_Node);
  1452.  
  1453.       --  Otherwise it's enough to compare the line numbers and chars.
  1454.  
  1455.       else
  1456.          Namet.Get_Name_String (Chars (Entity_Node));
  1457.  
  1458.       end if;
  1459.  
  1460.       --  First we look if the entity is already in the list.
  1461.  
  1462.       while not Found loop
  1463.          if New_Entity = null then
  1464.  
  1465.             Add_Entity (To_Etbl, Entity_Node, New_Entity);
  1466.             Found := True;
  1467.  
  1468.          elsif New_Entity.Entity_Sloc = New_Sloc then
  1469.  
  1470.             if To_Etbl.Kind = Genr then
  1471.  
  1472.                if New_Entity.Scope_Path.all = Path_Ptr.all then
  1473.                   New_Entity.Entity_Node := Entity_Node;
  1474.                   Found := True;
  1475.                else
  1476.                   New_Entity := New_Entity.Next_Entity;
  1477.                end if;
  1478.  
  1479.             else
  1480.                if New_Entity.Chars.all = Name_Buffer (1 .. Name_Len) then
  1481.                   New_Entity.Entity_Node := Entity_Node;
  1482.                   Found := True;
  1483.                else
  1484.                   New_Entity := New_Entity.Next_Entity;
  1485.                end if;
  1486.  
  1487.             end if;
  1488.  
  1489.          else
  1490.             New_Entity := New_Entity.Next_Entity;
  1491.  
  1492.          end if;
  1493.       end loop;
  1494.  
  1495.    end Update_Entity;
  1496.  
  1497.    ----------------------
  1498.    -- Update_Reference --
  1499.    ----------------------
  1500.  
  1501.    procedure Update_Reference
  1502.      (To_Entity :  Entity_Acc;
  1503.       New_Etbl  :  Entity_Table_Acc;
  1504.       New_Ref   :  Node_Id)
  1505.    is
  1506.       R_Tmp : Ref_Acc;
  1507.       --  To store the current values within the search loop.
  1508.  
  1509.       New_Sloc : Source_Ptr  := Sloc (New_Ref);
  1510.       Found    : Boolean     := False;
  1511.  
  1512.    begin
  1513.       if To_Entity /= null then
  1514.  
  1515.          --  We look if the reference is already in the list.
  1516.  
  1517.          R_Tmp := To_Entity.First_Ref;
  1518.  
  1519.          while not Found loop
  1520.             if R_Tmp = null then
  1521.                Add_Reference (To_Entity, New_Etbl, New_Ref);
  1522.                Found  := True;
  1523.  
  1524.             elsif R_Tmp.Etbl = New_Etbl
  1525.               and then R_Tmp.Sloc = New_Sloc
  1526.             then
  1527.                --  In this case we update only the Node_Id.
  1528.  
  1529.                R_Tmp.Ref_Node    := New_Ref;
  1530.                Found := True;
  1531.  
  1532.             else
  1533.                R_Tmp := R_Tmp.Next_Ref;
  1534.             end if;
  1535.          end loop;
  1536.  
  1537.       end if;
  1538.    end Update_Reference;
  1539.  
  1540.    ----------------------
  1541.    -- Write_Files_Info --
  1542.    ----------------------
  1543.  
  1544.    procedure Write_Files_Info (The_Etbl : Entity_Table_Acc) is
  1545.       The_Withs     : With_Acc;
  1546.       The_Includes  : Include_Acc;
  1547.       List_Etbl     : Entity_Table_Acc;
  1548.       Parent_Unit   : Unit_Number_Type;
  1549.       Unit_Node     : Node_Id;
  1550.  
  1551.    begin
  1552.       Buffer_Length := 0;
  1553.  
  1554.       Indent := Entity_Indent;
  1555.  
  1556.       --  Add the name of the file in the buffer
  1557.  
  1558.       Add_Str_To_Buffer (The_Etbl.File_Name.all);
  1559.       Add_Tabs_To_Buffer;
  1560.  
  1561.       --  Then add the time stamp of the file
  1562.  
  1563.       Add_Str_To_Buffer (The_Etbl.Time_Stamp);
  1564.       Add_Char_To_Buffer (' ');
  1565.  
  1566.       case The_Etbl.Status is
  1567.  
  1568.          when A_Spec | Withed_Spec =>
  1569.  
  1570.             --  We check if the Etbl is child library spec.
  1571.  
  1572.             Unit_Node := Unit (The_Etbl.Top_Node);
  1573.             if Parent_Spec (Unit_Node) /= Empty then
  1574.                Parent_Unit := Get_Cunit_Unit_Number (Parent_Spec (Unit_Node));
  1575.                Add_Nat_To_Buffer (Nat (Parent_Unit) + 1);
  1576.                Add_Char_To_Buffer (' ');
  1577.             end if;
  1578.  
  1579.          when A_Body  =>
  1580.  
  1581.             --  The spec of a body must appear in the inclusion graph
  1582.  
  1583.             Add_Nat_To_Buffer (Nat (The_Etbl.Predecessor.Unit_Number) + 1);
  1584.             Add_Char_To_Buffer (' ');
  1585.  
  1586.             --  All the subunits of the body are included.
  1587.  
  1588.             List_Etbl := The_Etbl.Successor;
  1589.             while List_Etbl /= null loop
  1590.                Add_Nat_To_Buffer (Nat (List_Etbl.Unit_Number) + 1);
  1591.                Add_Char_To_Buffer (' ');
  1592.                List_Etbl := List_Etbl.Successor;
  1593.             end loop;
  1594.  
  1595.          when Sub_Body =>
  1596.             Add_Nat_To_Buffer (Nat (The_Etbl.Predecessor.Unit_Number) + 1);
  1597.             Add_Char_To_Buffer (' ');
  1598.  
  1599.          when others   =>
  1600.             null;
  1601.  
  1602.       end case;
  1603.  
  1604.       The_Includes := The_Etbl.First_Include;
  1605.       while The_Includes /= null loop
  1606.  
  1607.          --  In the case we find a generic instantiation, we have added to
  1608.          --  the include list the spec where the generic is defined
  1609.          --  in the inclusion graph we want to get
  1610.  
  1611.          --     - the spec, if it is not withed by the Etbl
  1612.          --     - the bodies corresponding to the spec
  1613.  
  1614.          List_Etbl := The_Includes.Included_Etbl;
  1615.  
  1616.          if not In_With_List (List_Etbl, The_Etbl) then
  1617.             Add_Nat_To_Buffer (Nat (List_Etbl.Unit_Number) + 1);
  1618.             Add_Char_To_Buffer (' ');
  1619.          end if;
  1620.  
  1621.          List_Etbl := List_Etbl.Successor;
  1622.          while List_Etbl /= null loop
  1623.             Add_Nat_To_Buffer (Nat (List_Etbl.Unit_Number) + 1);
  1624.             Add_Char_To_Buffer (' ');
  1625.             List_Etbl := List_Etbl.Successor;
  1626.          end loop;
  1627.  
  1628.          The_Includes := The_Includes.Next_Include;
  1629.       end loop;
  1630.  
  1631.       The_Withs := The_Etbl.First_With;
  1632.       while The_Withs /= null loop
  1633.          Add_Nat_To_Buffer (Nat (The_Withs.Withed_Etbl.Unit_Number) + 1);
  1634.          Add_Char_To_Buffer (' ');
  1635.          The_Withs := The_Withs.Next_With;
  1636.       end loop;
  1637.  
  1638.       Write_Xref_Info (Buffer (1 .. Buffer_Length));
  1639.       Buffer_Length := 0;
  1640.  
  1641.    end Write_Files_Info;
  1642.  
  1643.    -------------------
  1644.    -- Write_Version --
  1645.    -------------------
  1646.  
  1647.    procedure Write_Version is
  1648.    begin
  1649.       Indent := Entity_Indent;
  1650.       Add_Str_To_Buffer ("V ");
  1651.       Add_Char_To_Buffer ('"');
  1652.       Add_Str_To_Buffer (Gnatvsn.Xref_Version);
  1653.       Add_Char_To_Buffer ('"');
  1654.       Write_Xref_Info (Buffer (1 .. Buffer_Length));
  1655.       Buffer_Length := 0;
  1656.  
  1657.    end Write_Version;
  1658.  
  1659.    ----------
  1660.    -- Writ --
  1661.    ----------
  1662.  
  1663.    --  This procedure is over 1400 lines long with doubly nested internal
  1664.    --  subprograms, it should be simplified and flattened out, with less
  1665.    --  use (if necessary) of non-local variables. ???
  1666.  
  1667.    procedure Writ
  1668.      (The_Etbl   : Entity_Table_Acc;
  1669.       Level      : Output_Level;
  1670.       First_File : Boolean)
  1671.    is
  1672.       Warning_String_3  : constant String := "withed but unused";
  1673.       Warning_String_5  : constant String := " in ";
  1674.       Warning_String_10 : constant String := " should be withed";
  1675.       Warning_String_12 : constant String := "already withed in ";
  1676.  
  1677.       E_Tmp            : Entity_Acc;
  1678.       --  To store the current entity within the search loop.
  1679.  
  1680.       Has_Inlined      : Boolean := False;
  1681.       --  Flag set in the corresponding spec of a body or a subunit
  1682.       --  declares Inlined procedures or functions
  1683.  
  1684.       Etbl_Prec        : Entity_Table_Acc;
  1685.  
  1686.       Real_Checked     : Entity_Table_Acc;
  1687.  
  1688.       The_Withs        : With_Acc;
  1689.  
  1690.       First_Refs       : Boolean := True;
  1691.  
  1692.       --  The following variables allow to know, if a parent spec of a
  1693.       --  withed spec is used in the_etebl and which parent.
  1694.  
  1695.       Is_Parent_Used : Boolean;
  1696.  
  1697.       Parent_Used : Entity_Table_Acc;
  1698.  
  1699.       function Renamed_Etbl
  1700.         (Current_Etbl : Entity_Table_Acc)
  1701.          return         Entity_Table_Acc;
  1702.       --  Returns the entitiy table table corresponding to the unit
  1703.       --  renamed in Current_Etbl
  1704.  
  1705.       procedure Check_Parents (Withed_Etbl : Entity_Table_Acc);
  1706.       --  Checks if parent spec of withed spec have references in The_Etbl
  1707.  
  1708.       procedure Check_Withing_Units;
  1709.       --  Checks references to The_Etbl in entity tables that with The_Etbl
  1710.  
  1711.       procedure Check_Withed_Units;
  1712.       --  Check the correct use of the withed units of The_Etbl.
  1713.  
  1714.       procedure Write_References (First : Ref_Acc; Only_Marked : Boolean);
  1715.       --  Places the reference string of a given entity in Buffer. The
  1716.       --  reference string consists of source name files followed by the
  1717.       --  line numbers of the references within these files. Only_Marked
  1718.       --  is a flag to indicate if we cnsider all the references or only
  1719.       --  the marked references.
  1720.  
  1721.       procedure Write_Warning (The_Entity : Entity_Acc);
  1722.       --  Places a warning message in Buffer and writes a warning message to
  1723.       --  standard output if an entity is not used within its program unit.
  1724.  
  1725.       type Withed_Warning_Type is
  1726.         (Norm,
  1727.          Should,
  1728.          Already,
  1729.          Replace,
  1730.          Should_Replace);
  1731.       --  This need doumentation for each case
  1732.  
  1733.       procedure Write_Withed_Warning
  1734.         (Withing_Etbl : Entity_Table_Acc;
  1735.          Warning_Kind : Withed_Warning_Type;
  1736.          Extra_Etbl   : Entity_Table_Acc);
  1737.       --  Writes warnings messages on the standard error.
  1738.       --
  1739.       --   1.) a withed unit is not used (Norm).
  1740.       --         Here the field Extra_Etbl is redundant.
  1741.       --
  1742.       --   2.) the same with clause appears within a predecessor (Already).
  1743.       --        ' ->  already in Extra_Etbl'
  1744.       --
  1745.       --   3.) a with clause should be moved into a successor (Should).
  1746.       --        ' ->  should be in Extra_Etbl'.
  1747.  
  1748.       ------------------
  1749.       -- Renamed_Etbl --
  1750.       ------------------
  1751.  
  1752.       function Renamed_Etbl
  1753.         (Current_Etbl : Entity_Table_Acc)
  1754.          return         Entity_Table_Acc
  1755.       is
  1756.       begin
  1757.          if Current_Etbl.Renamed_Etbl /= null then
  1758.             return Current_Etbl.Renamed_Etbl;
  1759.          else
  1760.             return Current_Etbl;
  1761.          end if;
  1762.       end Renamed_Etbl;
  1763.  
  1764.       -------------------
  1765.       -- Check_Parents --
  1766.       -------------------
  1767.       procedure Check_Parents (Withed_Etbl : Entity_Table_Acc) is
  1768.          Parent_Etbl : Entity_Table_Acc;
  1769.  
  1770.       begin
  1771.          Parent_Etbl := Withed_Etbl.Predecessor;
  1772.          while Parent_Etbl /= null loop
  1773.  
  1774.             Real_Checked := Renamed_Etbl (Parent_Etbl);
  1775.             Clear_And_Mark_Xrefs (Real_Checked, The_Etbl, True, True);
  1776.  
  1777.             if The_Etbl.Marked then
  1778.                Is_Parent_Used := True;
  1779.                if Parent_Used = null then
  1780.                   Parent_Used := Parent_Etbl;
  1781.                end if;
  1782.             end if;
  1783.  
  1784.             Parent_Etbl := Parent_Etbl.Predecessor;
  1785.          end loop;
  1786.       end Check_Parents;
  1787.  
  1788.       -------------------------
  1789.       -- Check_Withing_Units --
  1790.       -------------------------
  1791.       procedure Check_Withing_Units is
  1792.  
  1793.          First        : Boolean := True;
  1794.          Etbl_Tmp     : Entity_Table_Acc;
  1795.          Withing_Etbl : Entity_Table_Acc;
  1796.          Etbl_Succ    : Entity_Table_Acc;
  1797.  
  1798.       begin
  1799.          Etbl_Tmp := First_Etbl;
  1800.  
  1801.          while Etbl_Tmp /= null loop
  1802.             if Etbl_Tmp.Predecessor = null then
  1803.                if Etbl_Tmp = The_Etbl then
  1804.                   Withing_Etbl := Etbl_Tmp.Successor;
  1805.                else
  1806.                   Withing_Etbl := Etbl_Tmp;
  1807.                   while Withing_Etbl /= null
  1808.                     and then not In_With_List (The_Etbl, Withing_Etbl)
  1809.                   loop
  1810.                      Withing_Etbl := Withing_Etbl.Successor;
  1811.                   end loop;
  1812.                end if;
  1813.  
  1814.                Etbl_Succ := Withing_Etbl;
  1815.  
  1816.                while Etbl_Succ /= null loop
  1817.                   if Etbl_Succ.RU then
  1818.  
  1819.                      Clear_And_Mark_Xrefs
  1820.                        (The_Etbl, Etbl_Succ, First, False, True);
  1821.                      First := False;
  1822.                   end if;
  1823.                   Etbl_Succ := Etbl_Succ.Successor;
  1824.                end loop;
  1825.  
  1826.             end if;
  1827.             Etbl_Tmp := Etbl_Tmp.Next_Etbl;
  1828.          end loop;
  1829.       end Check_Withing_Units;
  1830.  
  1831.       ------------------------
  1832.       -- Check_Withed_Units --
  1833.       ------------------------
  1834.  
  1835.       procedure Check_Withed_Units is
  1836.          The_Withs : With_Acc := The_Etbl.First_With;
  1837.          --  Used to scan all the with of The_Etbl
  1838.  
  1839.          Etbl_Prec : Entity_Table_Acc;
  1840.          --  Predecessor of The_Etbl
  1841.  
  1842.          Etbl_Succ : Entity_Table_Acc;
  1843.          --  Successor of The_Etbl
  1844.  
  1845.          Real_Checked  : Entity_Table_Acc;
  1846.  
  1847.          Succ_Used     : Boolean;
  1848.          Previous_Refs : Boolean;
  1849.          Higher_Prec   : Entity_Table_Acc;
  1850.  
  1851.          function With_Ref
  1852.            (Target_Etbl : Entity_Table_Acc;
  1853.             Home_Etbl   : Entity_Table_Acc)
  1854.             return        With_Acc;
  1855.          --  Looks for the With Clause of Home_Etb in Target_Etbl
  1856.  
  1857.          procedure Messages_For_Succ
  1858.            (The_Message   : Withed_Messages;
  1859.             Extra_Etbl    : Entity_Table_Acc);
  1860.          --  This procedure scans all the successors of an Entity Table
  1861.          --  If a successor with an Unit which is already withed by The_Etbl
  1862.          --  then Store a message to print it later
  1863.  
  1864.          procedure Messages_For_Child
  1865.            (Base_Etbl     : Entity_Table_Acc;
  1866.             The_Message   : Withed_Messages;
  1867.             Extra_Etbl    : Entity_Table_Acc);
  1868.          --  This procedure scans all the childs of an Entity table
  1869.          --  if one of these childs withs a unit withed by the Etbl
  1870.          --  then we store the appropriate message to print it later
  1871.  
  1872.          procedure Store_Messages
  1873.            (Withed_Etbl : Entity_Table_Acc;
  1874.             The_Message : Withed_Messages;
  1875.             Extra_Etbl  : Entity_Table_Acc);
  1876.          --  Update the warning messages concerning the with clause
  1877.          --  of withed_Etbl in the successors or the child libraries
  1878.          --  of the_etbl
  1879.  
  1880.  
  1881.          --------------
  1882.          -- With_Ref --
  1883.          --------------
  1884.  
  1885.          function With_Ref
  1886.            (Target_Etbl : Entity_Table_Acc;
  1887.             Home_Etbl   : Entity_Table_Acc)
  1888.             return        With_Acc
  1889.          is
  1890.             With_List : With_Acc := Target_Etbl.First_With;
  1891.  
  1892.          begin
  1893.             while With_List /= null loop
  1894.                if With_List.Withed_Etbl = Home_Etbl then
  1895.                   return With_List;
  1896.                end if;
  1897.  
  1898.                With_List := With_List.Next_With;
  1899.             end loop;
  1900.          end With_Ref;
  1901.  
  1902.          -----------------------
  1903.          -- Messages_For_Succ --
  1904.          -----------------------
  1905.  
  1906.          procedure Messages_For_Succ
  1907.            (The_Message   : Withed_Messages;
  1908.             Extra_Etbl    : Entity_Table_Acc)
  1909.          is
  1910.             Parent_Etbl : Entity_Table_Acc;
  1911.  
  1912.          begin
  1913.             --  The_Etbl with The_Withs.Withed_Etbl. For all the successors
  1914.             --  of The_Etbl, which with The_Withs.Withed_Etbl or one of
  1915.             --  its parent spec, we store The_Message in the corresponding
  1916.             --  with structure.
  1917.  
  1918.             while Etbl_Succ /= null loop
  1919.                if In_With_List (The_Withs.Withed_Etbl, Etbl_Succ) then
  1920.                   Store_Messages
  1921.                     (The_Withs.Withed_Etbl, The_Message, Extra_Etbl);
  1922.                end if;
  1923.  
  1924.                Parent_Etbl := The_Withs.Withed_Etbl.Predecessor;
  1925.                while Parent_Etbl /= null loop
  1926.                   if In_With_List (Parent_Etbl, Etbl_Succ) then
  1927.                      Store_Messages
  1928.                        (Parent_Etbl, The_Message, Extra_Etbl);
  1929.                   end if;
  1930.                   Parent_Etbl := Parent_Etbl.Predecessor;
  1931.                end loop;
  1932.  
  1933.                Etbl_Succ := Etbl_Succ.Successor;
  1934.             end loop;
  1935.          end Messages_For_Succ;
  1936.  
  1937.          ------------------------
  1938.          -- Messages_For_Child --
  1939.          ------------------------
  1940.  
  1941.          procedure Messages_For_Child
  1942.            (Base_Etbl   : Entity_Table_Acc;
  1943.             The_Message : Withed_Messages;
  1944.             Extra_Etbl  : Entity_Table_Acc)
  1945.          is
  1946.             Childs      : Child_Spec_Acc := Base_Etbl.First_Child;
  1947.             --  ??? does childs here mean child spec, or is it the plural
  1948.             --  of child, if the latter, the English word is children, if
  1949.             --  the former, childspec would be a much more comfortable name
  1950.             Parent_Etbl : Entity_Table_Acc;
  1951.  
  1952.          begin
  1953.             --  The_Etbl with The_Withs.Withed_Etbl. For all the child
  1954.             --  libraries of The_Etbl, which with The_Withs.Withed_Etbl
  1955.             --  or one of its parent spec, we store The_Message in the
  1956.             --  corresponding with structure.
  1957.  
  1958.             while Childs /= null loop
  1959.                if In_With_List (The_Withs.Withed_Etbl, Childs.Child_Etbl) then
  1960.                   Store_Messages
  1961.                     (The_Withs.Withed_Etbl, The_Message, Extra_Etbl);
  1962.                end if;
  1963.  
  1964.                Parent_Etbl := The_Withs.Withed_Etbl.Predecessor;
  1965.                while Parent_Etbl /= null loop
  1966.                   if In_With_List (Parent_Etbl, Etbl_Succ) then
  1967.                      Store_Messages
  1968.                        (Parent_Etbl, The_Message, Extra_Etbl);
  1969.                   end if;
  1970.                   Parent_Etbl := Parent_Etbl.Predecessor;
  1971.                end loop;
  1972.  
  1973.                Etbl_Succ := Childs.Child_Etbl.Successor;
  1974.                Messages_For_Succ (The_Message, Extra_Etbl);
  1975.  
  1976.                --  We use a recursive call to visit all the child specs
  1977.                --  and not only the child specs of Base_Etbl.
  1978.  
  1979.                Messages_For_Child (Childs.Child_Etbl, The_Message, Extra_Etbl);
  1980.                Childs := Childs.Next_Child;
  1981.             end loop;
  1982.          end Messages_For_Child;
  1983.  
  1984.          --------------------
  1985.          -- Store_Messages --
  1986.          --------------------
  1987.  
  1988.          procedure Store_Messages
  1989.            (Withed_Etbl : Entity_Table_Acc;
  1990.             The_Message : Withed_Messages;
  1991.             Extra_Etbl  : Entity_Table_Acc)
  1992.          is
  1993.             Other_With : With_Acc;
  1994.  
  1995.          begin
  1996.  
  1997.             Other_With := With_Ref (Etbl_Succ, Withed_Etbl);
  1998.  
  1999.             if Other_With.Prev_Msgs = None then
  2000.                Other_With.Prev_Msgs := The_Message;
  2001.  
  2002.                if Extra_Etbl /= null then
  2003.                   Other_With.Extra_Etbl := Extra_Etbl;
  2004.                end if;
  2005.             end if;
  2006.  
  2007.          end Store_Messages;
  2008.  
  2009.       begin
  2010.          --  Scans all the withed units
  2011.  
  2012.          while The_Withs /= null loop
  2013.  
  2014.             --  Looks for references of the withed unit in The_Etbl
  2015.  
  2016.             Real_Checked := Renamed_Etbl (The_Withs.Withed_Etbl);
  2017.  
  2018.             --  Check if a message has already been stored for this
  2019.             --  with clause
  2020.  
  2021.             if The_Withs.Prev_Msgs = Already_Withed then
  2022.                Write_Withed_Warning
  2023.                  (The_Withs.Withed_Etbl, Already, The_Withs.Extra_Etbl);
  2024.             elsif The_Withs.Prev_Msgs = Withed_Unused then
  2025.                Write_Withed_Warning (The_Withs.Withed_Etbl, Norm, null);
  2026.             elsif The_Withs.Is_Implicit then
  2027.                Clear_And_Mark_Xrefs
  2028.                  (The_Withs.Withed_Etbl, The_Etbl, True, True);
  2029.             elsif The_Withs.Prev_Msgs = None then
  2030.  
  2031.                Is_Parent_Used := False;
  2032.                Parent_Used := null;
  2033.                Clear_And_Mark_Xrefs (Real_Checked, The_Etbl, True, True);
  2034.                Succ_Used := The_Etbl.Marked;
  2035.                Check_Parents (The_Withs.Withed_Etbl);
  2036.                The_Etbl.Marked := Succ_Used;
  2037.  
  2038.                --  If the only references found in The_Etbl are references to
  2039.                --  entities defined in a parent spec of the withed unit then
  2040.                --  The_Etbl mustn't be considered as using the withed unit.
  2041.  
  2042.                Previous_Refs := False;
  2043.                Etbl_Prec := The_Etbl.Predecessor;
  2044.  
  2045.                while Etbl_Prec /= null loop
  2046.                   if In_With_List (The_Withs.Withed_Etbl, Etbl_Prec) then
  2047.                      Clear_And_Mark_Xrefs
  2048.                        (Real_Checked, Etbl_Prec, False, False);
  2049.  
  2050.                      if Etbl_Prec.Marked then
  2051.                         Previous_Refs := True;
  2052.                         Higher_Prec := Etbl_Prec;
  2053.                      end if;
  2054.                   end if;
  2055.  
  2056.                   Etbl_Prec := Etbl_Prec.Predecessor;
  2057.                end loop;
  2058.  
  2059.                if Previous_Refs or else The_Etbl.Marked then
  2060.  
  2061.                   --  If references are found in a predecessors,
  2062.                   --  Message : Already withed in the predecessor
  2063.                   --  If references are found in The_Etbl,
  2064.                   --  Message : Already withed in The_Etbl
  2065.  
  2066.                   if Previous_Refs then
  2067.                      Write_Withed_Warning
  2068.                        (The_Withs.Withed_Etbl, Already, Higher_Prec);
  2069.                   else
  2070.                      Higher_Prec := The_Etbl;
  2071.                   end if;
  2072.  
  2073.                   if The_Etbl.Status /= Sub_Body then
  2074.                      Etbl_Succ := The_Etbl.Successor;
  2075.                      Messages_For_Succ (Already_Withed, Higher_Prec);
  2076.                   end if;
  2077.  
  2078.                   if The_Etbl.Status in Spec_Status then
  2079.                      Messages_For_Child
  2080.                        (The_Etbl, Already_Withed, Higher_Prec);
  2081.                   end if;
  2082.  
  2083.                else
  2084.                   case The_Etbl.Status is
  2085.                      when Sub_Body =>
  2086.                         if not Is_Parent_Used then
  2087.                            Write_Withed_Warning
  2088.                              (The_Withs.Withed_Etbl, Norm, null);
  2089.                         else
  2090.                            Write_Withed_Warning
  2091.                              (The_Withs.Withed_Etbl, Replace, Parent_Used);
  2092.                         end if;
  2093.  
  2094.                      when others   =>
  2095.  
  2096.                         Succ_Used := False;
  2097.                         Etbl_Succ := The_Etbl.Successor;
  2098.  
  2099.                         --  We search the closest parent Parent_Used
  2100.                         --  of the withed unit which has references
  2101.                         --  in a successor of The_Etbl
  2102.  
  2103.                         while Etbl_Succ /= null loop
  2104.  
  2105.                            Etbl_Prec := The_Withs.Withed_Etbl;
  2106.  
  2107.                            while Etbl_Prec /= Parent_Used loop
  2108.                               Real_Checked := Renamed_Etbl (Etbl_Prec);
  2109.                               Clear_And_Mark_Xrefs
  2110.                                 (Real_Checked, Etbl_Succ, False, False);
  2111.  
  2112.                               if Etbl_Succ.Marked then
  2113.                                  Succ_Used := True;
  2114.                                  Parent_Used := Etbl_Prec;
  2115.  
  2116.                                  --  As soon as we find a reference in a
  2117.                                  --  successor to a parent spec, we exit
  2118.  
  2119.                                  exit;
  2120.                               end if;
  2121.  
  2122.                               Etbl_Prec := Etbl_Prec.Predecessor;
  2123.                            end loop;
  2124.  
  2125.                            --  If the withed unit is not a child spec, as soon
  2126.                            --  as we find a reference in a successor, we can
  2127.                            --  exit otherwise, we scan all the successors to
  2128.                            --  see which parent should replace the withed unit.
  2129.  
  2130.                            if The_Withs.Withed_Etbl.Predecessor = null then
  2131.                               exit when Succ_Used;
  2132.                            end if;
  2133.  
  2134.                            Etbl_Succ := Etbl_Succ.Successor;
  2135.                         end loop;
  2136.  
  2137.                         if The_Etbl.Status in Spec_Status then
  2138.  
  2139.                            --  Many cases must be checked :
  2140.  
  2141.                            --   1 - The_Etbl uses some entities defined in
  2142.                            --   a parent spec of the withed unit. In this
  2143.                            --   case, the with clause is incorrect.
  2144.                            --   Parent_Used should be withed (if the withed
  2145.                            --   unit is not directly used in a successor);
  2146.  
  2147.                            --   2 - If no references are found in
  2148.                            --   The_Etbl but some references to the withed
  2149.                            --   unit are found in a successopr, then the
  2150.                            --   with clause shouldn't be in the spec,
  2151.                            --   but in the body
  2152.  
  2153.                            --   3 - if no references are found in any
  2154.                            --   successor,  Message : Withefd but unused
  2155.  
  2156.                            --   4 - If a reference to a parent spec of
  2157.                            --   the withed unit has been found in a
  2158.                            --   successor then Message : Parent_Used
  2159.                            --   should be withed in the body
  2160.  
  2161.                            if Is_Parent_Used then
  2162.                               if Parent_Used /= The_Withs.Withed_Etbl then
  2163.                                  if not In_With_List
  2164.                                           (Parent_Used, The_Etbl) then
  2165.                                     Write_Withed_Warning
  2166.                                       (The_Withs.Withed_Etbl, Replace,
  2167.                                        Parent_Used);
  2168.                                  else
  2169.                                     Write_Withed_Warning
  2170.                                       (The_Withs.Withed_Etbl, Norm, null);
  2171.                                  end if;
  2172.  
  2173.                                  Etbl_Succ := The_Etbl.Successor;
  2174.                                  Messages_For_Succ (Already_Withed, The_Etbl);
  2175.                               end if;
  2176.  
  2177.                            elsif Parent_Used = The_Withs.Withed_Etbl then
  2178.                               Etbl_Succ := The_Etbl.Successor;
  2179.                               if Etbl_Succ /= null then
  2180.                                  if not In_With_List
  2181.                                      (The_Withs.Withed_Etbl, Etbl_Succ)
  2182.                                  then
  2183.                                     Write_Withed_Warning
  2184.                                       (The_Withs.Withed_Etbl,
  2185.                                        Should, Etbl_Succ);
  2186.                                  end if;
  2187.  
  2188.                                  Etbl_Succ := Etbl_Succ.Successor;
  2189.                                  Messages_For_Succ (Already_Withed, The_Etbl);
  2190.                               end if;
  2191.  
  2192.                            elsif Parent_Used = null then
  2193.                               Write_Withed_Warning
  2194.                                 (The_Withs.Withed_Etbl, Norm, null);
  2195.                               Etbl_Succ := The_Etbl.Successor;
  2196.                               Messages_For_Succ (Withed_Unused, null);
  2197.  
  2198.                            else
  2199.                               Etbl_Succ := The_Etbl.Successor;
  2200.  
  2201.                               if Etbl_Succ /= null then
  2202.  
  2203.                                  if not
  2204.                                    In_With_List (Parent_Used, Etbl_Succ)
  2205.                                  then
  2206.                                     Write_Withed_Warning
  2207.                                       (The_Withs.Withed_Etbl,
  2208.                                        Should_Replace, Parent_Used);
  2209.                                  end if;
  2210.  
  2211.                                  Etbl_Succ := Etbl_Succ.Successor;
  2212.                                  Messages_For_Succ (Already_Withed, The_Etbl);
  2213.                               end if;
  2214.                            end if;
  2215.  
  2216.                         else
  2217.                            --  If we found a reference to the withed unit in a
  2218.                            --  successor, then no message for the current Etbl
  2219.                            --  but messages "already withed" for successors.
  2220.  
  2221.                            --  If no reference to the withed unit or one of
  2222.                            --  its parents has been found then message
  2223.                            --  "withed unused".
  2224.  
  2225.                            --  If a reference to a parent of the withed
  2226.                            --  unit has been found, message "should be
  2227.                            --  replaced by"
  2228.  
  2229.                            if Parent_Used = The_Withs.Withed_Etbl then
  2230.                               Etbl_Succ := The_Etbl.Successor;
  2231.                               Messages_For_Succ (Already_Withed, The_Etbl);
  2232.  
  2233.                            elsif Parent_Used = null then
  2234.                               Write_Withed_Warning
  2235.                                 (The_Withs.Withed_Etbl, Norm, null);
  2236.                               Etbl_Succ := The_Etbl.Successor;
  2237.                               Messages_For_Succ (Withed_Unused, null);
  2238.  
  2239.                            else
  2240.                               if not In_With_List (Parent_Used, The_Etbl) then
  2241.                                  Write_Withed_Warning
  2242.                                    (The_Withs.Withed_Etbl, Replace,
  2243.                                     Parent_Used);
  2244.                               else
  2245.                                  Write_Withed_Warning
  2246.                                    (The_Withs.Withed_Etbl, Norm, null);
  2247.                               end if;
  2248.  
  2249.                               Etbl_Succ := The_Etbl.Successor;
  2250.                               Messages_For_Succ (Already_Withed, The_Etbl);
  2251.                            end if;
  2252.                         end if;
  2253.  
  2254.                   end case;
  2255.  
  2256.                end if;
  2257.             end if;
  2258.  
  2259.             The_Withs.Prev_Msgs := Done;
  2260.             The_Withs := The_Withs.Next_With;
  2261.  
  2262.          end loop;
  2263.       end Check_Withed_Units;
  2264.  
  2265.       -----------------------------
  2266.       -- Write_References --
  2267.       -----------------------------
  2268.  
  2269.       procedure Write_References
  2270.         (First       : Ref_Acc;
  2271.          Only_Marked : Boolean)
  2272.       is
  2273.          Current_Ref   : Ref_Acc := First;
  2274.          Current_Etbl  : Entity_Table_Acc;
  2275.          Current_Line  : Logical_Line_Number;
  2276.          Current_Col   : Column_Number;
  2277.  
  2278.          Previous_Etbl : Entity_Table_Acc;
  2279.          Previous_Line : Int;
  2280.          Previous_Col  : Int;
  2281.          --  These variables are used to suppress the repetition of the
  2282.          --  same units and the same line numbers.
  2283.  
  2284.       begin
  2285.          --  Loop through all the references of the list.
  2286.  
  2287.          while Current_Ref /= null loop
  2288.  
  2289.             if (not Only_Marked or else Current_Ref.Marked)
  2290.               and then Current_Ref.Etbl.RU
  2291.             then
  2292.                Current_Etbl := Current_Ref.Etbl;
  2293.  
  2294.                --  If we find a reference in a new file we add the new
  2295.                --  file name and the line number.
  2296.  
  2297.                if Current_Etbl /= Previous_Etbl then
  2298.  
  2299.                   --  Suppress the } for the first file.
  2300.  
  2301.                   if Previous_Etbl /= null
  2302.                     and then Previous_Line /= -1
  2303.                   then
  2304.                      Add_Char_To_Buffer ('}');
  2305.                      Write_Xref_Info (Buffer (1 .. Buffer_Length));
  2306.                      Buffer_Length := 0;
  2307.                   end if;
  2308.  
  2309.                   Indent := Reference_Indent;
  2310.  
  2311.                   Previous_Etbl := Current_Etbl;
  2312.                   Previous_Line := -1;
  2313.  
  2314.                   if Global_Xref_File then
  2315.                      Add_Str_To_Buffer (Current_Etbl.File_Name.all);
  2316.                      Add_Char_To_Buffer (' ');
  2317.                   end if;
  2318.  
  2319.                   if Global_Xref_File or else Current_Etbl = The_Etbl then
  2320.                      Add_Char_To_Buffer ('{');
  2321.                   end if;
  2322.  
  2323.                end if;
  2324.  
  2325.                --  For each reference, we write in the xref file the line
  2326.                --  number and the column number where the reference was found
  2327.                --  in the following format : line(col)
  2328.  
  2329.                Current_Line := Current_Ref.Line_Number;
  2330.                Current_Col  := Current_Ref.Col_Number;
  2331.  
  2332.                if Global_Xref_File
  2333.                  or else Current_Ref.Etbl = The_Etbl
  2334.                then
  2335.                   --  Suppress the space for the first reference.
  2336.  
  2337.                   if (Previous_Line /= -1) then
  2338.                      Add_Char_To_Buffer (' ');
  2339.                   end if;
  2340.  
  2341.                   Previous_Line := Int (Current_Line);
  2342.                   Previous_Col  := Int (Current_Col);
  2343.  
  2344.                   Add_Nat_To_Buffer (Int (Current_Line));
  2345.                   Add_Char_To_Buffer (':');
  2346.                   Add_Nat_To_Buffer (Int (Current_Col));
  2347.                end if;
  2348.             end if;
  2349.  
  2350.             Current_Ref := Current_Ref.Next_Ref;
  2351.          end loop;
  2352.  
  2353.          if Previous_Etbl /= null
  2354.            and then Previous_Line /= -1 then
  2355.             Add_Char_To_Buffer ('}');
  2356.             Write_Xref_Info (Buffer (1 .. Buffer_Length));
  2357.             Buffer_Length := 0;
  2358.          end if;
  2359.  
  2360.       end Write_References;
  2361.  
  2362.       -------------------
  2363.       -- Write_Warning --
  2364.       -------------------
  2365.  
  2366.       procedure Write_Warning (The_Entity : Entity_Acc) is
  2367.          Parameters : Entity_Acc;
  2368.  
  2369.       begin
  2370.          if Entity_Warnings
  2371.            and then The_Entity.Length = 0
  2372.            and then The_Entity.Give_Warning
  2373.          then
  2374.             --  If the unused entity is a function or a procedure
  2375.             --  we don't want to output any messages about parameters
  2376.  
  2377.             if The_Entity.Entity_Type in Subprogram_Kind then
  2378.                Parameters := The_Entity.Next_Entity;
  2379.                while Parameters /= null
  2380.                  and then Parameters.Entity_Type in Formal_Kind
  2381.                loop
  2382.                   Parameters.Give_Warning := False;
  2383.                   Parameters := Parameters.Next_Entity;
  2384.                end loop;
  2385.             end if;
  2386.  
  2387.             --  Standard output
  2388.  
  2389.             The_Entity.Give_Warning := False;
  2390.             Error_Msg_Name_1 := The_Entity.Entity_Char;
  2391.             Error_Msg ("?% unused", The_Entity.Entity_Sloc);
  2392.  
  2393.          end if;
  2394.       end Write_Warning;
  2395.  
  2396.       --------------------------
  2397.       -- Write_Withed_Warning --
  2398.       --------------------------
  2399.  
  2400.       procedure Write_Withed_Warning
  2401.         (Withing_Etbl : Entity_Table_Acc;
  2402.          Warning_Kind : Withed_Warning_Type;
  2403.          Extra_Etbl   : Entity_Table_Acc)
  2404.       is
  2405.          Sloc_With        : Source_Ptr;
  2406.  
  2407.          Err_Length       : Integer;
  2408.          --  Length of the buffer which must be allocated for error
  2409.          --  messages.
  2410.  
  2411.          procedure Add_Str_To_Error_Buffer
  2412.            (The_String   : String;
  2413.             Error_Buffer : in out String);
  2414.          --  Adds The_String to the error Buffer;
  2415.  
  2416.          function Ref_Of_With return Source_Ptr;
  2417.          --  Searches and returns the node of the statement where The_Etbl
  2418.          --  is withed. If the node is not found the functions returns Empty
  2419.          --  and the compilation is abandonned
  2420.  
  2421.          procedure Add_Str_To_Error_Buffer
  2422.            (The_String   : String;
  2423.             Error_Buffer : in out String)
  2424.          is
  2425.          begin
  2426.             Error_Buffer (Err_Length .. Err_Length + The_String'Length - 1) :=
  2427.                             The_String;
  2428.             Err_Length := Err_Length + The_String'Length;
  2429.          end Add_Str_To_Error_Buffer;
  2430.  
  2431.          function Ref_Of_With return Source_Ptr is
  2432.             The_Ref : Ref_Acc := Withing_Etbl.First_Entity.First_Ref;
  2433.  
  2434.          begin
  2435.             while The_Ref /= null loop
  2436.                if The_Ref.Etbl = The_Etbl then
  2437.                   return The_Ref.Sloc;
  2438.                else
  2439.                   The_Ref := The_Ref.Next_Ref;
  2440.                end if;
  2441.             end loop;
  2442.  
  2443.             return No_Location;
  2444.  
  2445.          end Ref_Of_With;
  2446.  
  2447.       --  Start of processing for Write_Withed_Warning
  2448.  
  2449.       begin
  2450.          if With_Warnings then
  2451.             Sloc_With := Ref_Of_With;
  2452.  
  2453.             if Sloc_With /= No_Location then
  2454.  
  2455.                Error_Msg_Name_1 := Withing_Etbl.First_Entity.Entity_Char;
  2456.  
  2457.                if Warning_Kind = Replace
  2458.                  or else Warning_Kind = Should_Replace
  2459.                then
  2460.                   Error_Msg_Name_2 := Extra_Etbl.First_Entity.Entity_Char;
  2461.                end if;
  2462.  
  2463.                case Warning_Kind is
  2464.                   when Norm           =>
  2465.                      Err_Length := 3 + Warning_String_3'Length + 1;
  2466.  
  2467.                      declare
  2468.                         Err_Buffer : String (1 .. Err_Length);
  2469.  
  2470.                      begin
  2471.                         Err_Length := 1;
  2472.                         Add_Str_To_Error_Buffer ("?% ", Err_Buffer);
  2473.                         Add_Str_To_Error_Buffer
  2474.                           (Warning_String_3, Err_Buffer);
  2475.                         Err_Buffer (Err_Length .. Err_Length) := ".";
  2476.                         Error_Msg (Err_Buffer (1 .. Err_Length), Sloc_With);
  2477.                      end;
  2478.  
  2479.                   when Should         =>
  2480.                      Err_Length := 2 + Warning_String_10'Length
  2481.                        + Warning_String_5'Length
  2482.                        + Extra_Etbl.File_Name.all'Length + 1;
  2483.  
  2484.                      declare
  2485.                         Err_Buffer : String (1 .. Err_Length);
  2486.  
  2487.                      begin
  2488.                         Err_Length := 1;
  2489.                         Add_Str_To_Error_Buffer ("?%", Err_Buffer);
  2490.                         Add_Str_To_Error_Buffer
  2491.                           (Warning_String_10, Err_Buffer);
  2492.                         Add_Str_To_Error_Buffer
  2493.                           (Warning_String_5, Err_Buffer);
  2494.                         Add_Str_To_Error_Buffer
  2495.                           (Extra_Etbl.File_Name.all, Err_Buffer);
  2496.                         Err_Buffer (Err_Length .. Err_Length) := ".";
  2497.                         Error_Msg (Err_Buffer (1 .. Err_Length), Sloc_With);
  2498.                      end;
  2499.  
  2500.                   when Already        =>
  2501.                      Err_Length := 3 + Warning_String_12'Length
  2502.                        + Extra_Etbl.File_Name.all'Length + 1;
  2503.  
  2504.                      declare
  2505.                         Err_Buffer : String (1 .. Err_Length);
  2506.  
  2507.                      begin
  2508.                         Err_Length := 1;
  2509.                         Add_Str_To_Error_Buffer ("?% ", Err_Buffer);
  2510.                         Add_Str_To_Error_Buffer
  2511.                           (Warning_String_12, Err_Buffer);
  2512.                         Add_Str_To_Error_Buffer
  2513.                           (Extra_Etbl.File_Name.all, Err_Buffer);
  2514.                         Err_Buffer (Err_Length .. Err_Length) := ".";
  2515.                         Error_Msg (Err_Buffer (1 .. Err_Length), Sloc_With);
  2516.                      end;
  2517.  
  2518.                   when Replace        =>
  2519.                      Err_Length := 3 + Warning_String_3'Length + 3
  2520.                        + Warning_String_10'Length + 1;
  2521.  
  2522.                      declare
  2523.                         Err_Buffer : String (1 .. Err_Length);
  2524.  
  2525.                      begin
  2526.                         Err_Length := 1;
  2527.                         Add_Str_To_Error_Buffer ("?% ", Err_Buffer);
  2528.                         Add_Str_To_Error_Buffer
  2529.                           (Warning_String_3, Err_Buffer);
  2530.                         Add_Str_To_Error_Buffer (". %", Err_Buffer);
  2531.                         Add_Str_To_Error_Buffer
  2532.                           (Warning_String_10, Err_Buffer);
  2533.                         Err_Buffer (Err_Length .. Err_Length) := ".";
  2534.                         Error_Msg (Err_Buffer (1 .. Err_Length), Sloc_With);
  2535.                      end;
  2536.  
  2537.                   when Should_Replace =>
  2538.                      Err_Length := 3 + Warning_String_3'Length + 3
  2539.                        + Warning_String_10'Length + Warning_String_5'Length +
  2540.                        The_Etbl.Successor.File_Name.all'Length + 1;
  2541.  
  2542.                      declare
  2543.                         Err_Buffer : String (1 .. Err_Length);
  2544.  
  2545.                      begin
  2546.                         Err_Length := 1;
  2547.                         Add_Str_To_Error_Buffer ("?% ", Err_Buffer);
  2548.                         Add_Str_To_Error_Buffer
  2549.                           (Warning_String_3, Err_Buffer);
  2550.                         Add_Str_To_Error_Buffer (". %", Err_Buffer);
  2551.                         Add_Str_To_Error_Buffer
  2552.                           (Warning_String_10, Err_Buffer);
  2553.                         Add_Str_To_Error_Buffer
  2554.                           (Warning_String_5, Err_Buffer);
  2555.                         Add_Str_To_Error_Buffer
  2556.                           (The_Etbl.Successor.File_Name.all, Err_Buffer);
  2557.                         Err_Buffer (Err_Length .. Err_Length) := ".";
  2558.                         Error_Msg (Err_Buffer (1 .. Err_Length), Sloc_With);
  2559.                      end;
  2560.  
  2561.                      --  General note: especially appropriately addressed
  2562.                      --  to France! It is undesirable to construct messages
  2563.                      --  in this way, because it will make them hard to
  2564.                      --  automatically translate. Use a single string with
  2565.                      --  insertions always ???
  2566.  
  2567.                end case;
  2568.             end if;
  2569.          end if;
  2570.  
  2571.       end Write_Withed_Warning;
  2572.  
  2573.    --------------------------------------
  2574.    -- Start Processing for Write_Table --
  2575.    --------------------------------------
  2576.  
  2577.    begin
  2578.       Compiler_State := Analyzing;
  2579.       --  ??? the above is very strange, needs some comments
  2580.       --  ??? this really must be looked at, it is certainly a bug!
  2581.  
  2582.       case Level is
  2583.  
  2584.          when Full_Xref =>
  2585.  
  2586.             if Global_Xref_File then
  2587.  
  2588.                --  Write a pretty heading
  2589.  
  2590.                Write_Unit_Info (Header_Full, The_Etbl);
  2591.  
  2592.                Check_Withed_Units;
  2593.  
  2594.                --  Loop through all the entities in Entity_Table.
  2595.  
  2596.                E_Tmp := The_Etbl.First_Entity;
  2597.  
  2598.                while E_Tmp /= null loop
  2599.  
  2600.                   --  First we write the entity,
  2601.  
  2602.                   Write_Entity_Info (E_Tmp);
  2603.  
  2604.                   --  Give warnings if entity is not used. Still write warnings
  2605.                   --  to standard output even for entities declared in a body.
  2606.  
  2607.                   Write_Warning (E_Tmp);
  2608.  
  2609.                   --  If some references exist, then write them.
  2610.  
  2611.                   Write_Xref_Info (Buffer (1 .. Buffer_Length));
  2612.                   Buffer_Length := 0;
  2613.  
  2614.                   if E_Tmp.First_Ref /= null then
  2615.                      Indent := Reference_Indent;
  2616.                      Write_References (E_Tmp.First_Ref, False);
  2617.                   end if;
  2618.  
  2619.                   E_Tmp := E_Tmp.Next_Entity;
  2620.                end loop;
  2621.  
  2622.             else
  2623.                --  In xref levels 3 and 4, we write the following:
  2624.  
  2625.                --  For specs : entities declared in the spec and references
  2626.                --  to external entities
  2627.  
  2628.                --  For bodies and subunits : references to external entities
  2629.  
  2630.                if Include_Inlined and then not All_Info_In_Xref then
  2631.                   if The_Etbl.Status = A_Body then
  2632.                      Has_Inlined := The_Etbl.Predecessor.Has_Inlined;
  2633.  
  2634.                   elsif The_Etbl.Status = Sub_Body then
  2635.                      Etbl_Prec := The_Etbl.Predecessor;
  2636.                      while Etbl_Prec /= null
  2637.                        and then Etbl_Prec.Status not in Spec_Status loop
  2638.                         Etbl_Prec := Etbl_Prec.Predecessor;
  2639.                      end loop;
  2640.  
  2641.                      if Etbl_Prec /= null then
  2642.                         Has_Inlined := Etbl_Prec.Has_Inlined;
  2643.                      end if;
  2644.                   end if;
  2645.                end if;
  2646.  
  2647.                if First_File then
  2648.  
  2649.                   --  Before writing any informations in the xref file
  2650.                   --  we write all the file that have been loaded during
  2651.                   --  the compilation
  2652.  
  2653.                   Write_Unit_Info (Header_Full, The_Etbl);
  2654.  
  2655.                   if The_Etbl.Status = Sub_Body
  2656.                     and then not All_Info_In_Xref
  2657.                     and then not (Include_Inlined
  2658.                                     and then The_Etbl.First_Entity.Is_Direct)
  2659.                   then
  2660.                      --  In the case of subunit we write the name of the file
  2661.                      --  and the information about the subprogram of this unit.
  2662.  
  2663.                      Write_Entity_Info (The_Etbl.First_Entity);
  2664.  
  2665.                      Write_Xref_Info (Buffer (1 .. Buffer_Length));
  2666.                      Buffer_Length := 0;
  2667.                   end if;
  2668.                end if;
  2669.  
  2670.                E_Tmp := The_Etbl.First_Entity;
  2671.  
  2672.                while E_Tmp /= null loop
  2673.                   --  Below conditional is too complex ???
  2674.  
  2675.                   if First_File
  2676.                     and then ((The_Etbl.Status in Spec_Status
  2677.                                 and then E_Tmp.Entity_Type not in Formal_Kind
  2678.                                 and then E_Tmp.Entity_Type /= E_Discriminant)
  2679.                               or else ((The_Etbl.Status = A_Body
  2680.                                         or else The_Etbl.Status = Sub_Body)
  2681.                                        and then Has_Inlined
  2682.                                        and then E_Tmp.Is_Direct)
  2683.                               or else All_Info_In_Xref)
  2684.  
  2685.                   then
  2686.                      Write_Entity_Info (E_Tmp);
  2687.                   end if;
  2688.  
  2689.                   Write_Warning (E_Tmp);
  2690.  
  2691.                   --  Below conditional is too complex ???
  2692.  
  2693.                   if First_File
  2694.                     and then ((The_Etbl.Status in Spec_Status
  2695.                                 and then E_Tmp.Entity_Type not in Formal_Kind
  2696.                                 and then E_Tmp.Entity_Type /= E_Discriminant)
  2697.                               or else ((The_Etbl.Status = A_Body
  2698.                                          or else The_Etbl.Status = Sub_Body)
  2699.                                        and then Has_Inlined
  2700.                                        and then E_Tmp.Is_Direct)
  2701.                               or else All_Info_In_Xref)
  2702.                   then
  2703.                      Write_Xref_Info (Buffer (1 .. Buffer_Length));
  2704.                      Buffer_Length := 0;
  2705.  
  2706.                      if E_Tmp.First_Ref /= null then
  2707.                         Indent := Reference_Indent;
  2708.                         Write_References (E_Tmp.First_Ref, false);
  2709.                      end if;
  2710.                   end if;
  2711.  
  2712.                   E_Tmp := E_Tmp.Next_Entity;
  2713.  
  2714.                end loop;
  2715.  
  2716.                Check_Withed_Units;
  2717.  
  2718.                --  if the curret Etbl is not the main one we don't need
  2719.                --  to search references that are exported from predecessors
  2720.                --  or from units that are withed by the predecessors
  2721.  
  2722.                if First_File then
  2723.                   Etbl_Prec := The_Etbl.Predecessor;
  2724.  
  2725.                   while Etbl_Prec /= null loop
  2726.                      if Etbl_Prec.Status /= Sub_Body then
  2727.                         The_Withs := Etbl_Prec.First_With;
  2728.  
  2729.                         while The_Withs /= null loop
  2730.                            if not
  2731.                              In_With_List (The_Withs.Withed_Etbl, The_Etbl)
  2732.                              and then not The_Withs.Withed_Etbl.Xref_Written
  2733.                            then
  2734.                               Real_Checked  :=
  2735.                                 Renamed_Etbl (The_Withs.Withed_Etbl);
  2736.  
  2737.                               Clear_And_Mark_Xrefs
  2738.                                 (Real_Checked, The_Etbl, True, True, False);
  2739.  
  2740.                               if not The_Withs.Is_Implicit then
  2741.                                  Check_Parents (The_Withs.Withed_Etbl);
  2742.                               end if;
  2743.                            end if;
  2744.  
  2745.                            The_Withs := The_Withs.Next_With;
  2746.                         end loop;
  2747.  
  2748.                         Real_Checked := Renamed_Etbl (Etbl_Prec);
  2749.  
  2750.                         Clear_And_Mark_Xrefs
  2751.                           (Etbl_Prec, The_Etbl, True, True, False);
  2752.                      end if;
  2753.  
  2754.                      Etbl_Prec := Etbl_Prec.Predecessor;
  2755.                   end loop;
  2756.                end if;
  2757.  
  2758.             end if;
  2759.  
  2760.          when Smart_Xref =>
  2761.  
  2762.             --  Write a pretty heading
  2763.  
  2764.             if The_Etbl.Status = Withed_Spec then
  2765.                Write_Unit_Info (Header_Stub, The_Etbl);
  2766.             end if;
  2767.  
  2768.             Check_Withing_Units;
  2769.  
  2770.             --  We don't test if The_Etbl.Status = Withed_Spec because
  2771.             --  the Smart_Xref case is only treated for Withed_Spec.
  2772.  
  2773.             --  Loop through all the entities in Entity_Table.
  2774.  
  2775.             --  In this case we write something only if the entity is used
  2776.             --  within the target compilation unit.
  2777.  
  2778.             E_Tmp := The_Etbl.First_Entity;
  2779.  
  2780.             while E_Tmp /= null loop
  2781.  
  2782.                --  Don't write unmarked entities.
  2783.  
  2784.                if E_Tmp.Marks > 0 then
  2785.  
  2786.                   if First_Refs and then The_Etbl.Status = A_Spec then
  2787.                      Write_Unit_Info (Header_Stub, The_Etbl);
  2788.                      First_Refs := False;
  2789.                   end if;
  2790.  
  2791.                   --  First we write the entity,
  2792.  
  2793.                   Write_Entity_Info (E_Tmp);
  2794.  
  2795.                   --  And finally its references.
  2796.  
  2797.                   Write_Xref_Info (Buffer (1 .. Buffer_Length));
  2798.                   Buffer_Length := 0;
  2799.                   Indent := Reference_Indent;
  2800.                   Write_References (E_Tmp.First_Ref, True);
  2801.                end if;
  2802.  
  2803.                E_Tmp := E_Tmp.Next_Entity;
  2804.             end loop;
  2805.  
  2806.          when Full_Only_Standout =>
  2807.  
  2808.             Check_Withed_Units;
  2809.  
  2810.             --  Loop through all the entities in Entity_Table.
  2811.  
  2812.             E_Tmp := The_Etbl.First_Entity;
  2813.  
  2814.             while E_Tmp /= null loop
  2815.  
  2816.                Write_Warning (E_Tmp);
  2817.                --  Give warnings if the entity is not used.
  2818.  
  2819.                E_Tmp := E_Tmp.Next_Entity;
  2820.  
  2821.             end loop;
  2822.  
  2823.       end case;
  2824.  
  2825.    end Writ;
  2826.  
  2827. end Xref_Tab;
  2828.