OSDN Git Service

2007-02-13 Seongbae Park <seongbae.park@gmail.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / xr_tabls.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                             X R  _ T A B L S                             --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 1998-2006, Free Software Foundation, Inc.         --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
19 -- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20 -- Boston, MA 02110-1301, USA.                                              --
21 --                                                                          --
22 -- GNAT was originally developed  by the GNAT team at  New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
24 --                                                                          --
25 ------------------------------------------------------------------------------
26
27 with Types;    use Types;
28 with Osint;
29 with Hostparm;
30
31 with Ada.Unchecked_Conversion;
32 with Ada.Unchecked_Deallocation;
33 with Ada.Strings.Fixed;
34 with Ada.Strings;
35 with Ada.Text_IO;
36 with Ada.Characters.Handling;   use Ada.Characters.Handling;
37 with Ada.Strings.Unbounded;     use Ada.Strings.Unbounded;
38
39 with GNAT.OS_Lib;               use GNAT.OS_Lib;
40 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
41 with GNAT.HTable;               use GNAT.HTable;
42 with GNAT.Heap_Sort_G;
43
44 package body Xr_Tabls is
45
46    type HTable_Headers is range 1 .. 10000;
47
48    procedure Set_Next (E : File_Reference; Next : File_Reference);
49    function  Next (E : File_Reference) return File_Reference;
50    function  Get_Key (E : File_Reference) return Cst_String_Access;
51    function  Hash (F : Cst_String_Access) return HTable_Headers;
52    function  Equal (F1, F2 : Cst_String_Access) return Boolean;
53    --  The five subprograms above are used to instanciate the static
54    --  htable to store the files that should be processed.
55
56    package File_HTable is new GNAT.HTable.Static_HTable
57      (Header_Num => HTable_Headers,
58       Element    => File_Record,
59       Elmt_Ptr   => File_Reference,
60       Null_Ptr   => null,
61       Set_Next   => Set_Next,
62       Next       => Next,
63       Key        => Cst_String_Access,
64       Get_Key    => Get_Key,
65       Hash       => Hash,
66       Equal      => Equal);
67    --  A hash table to store all the files referenced in the
68    --  application.  The keys in this htable are the name of the files
69    --  themselves, therefore it is assumed that the source path
70    --  doesn't contain twice the same source or ALI file name
71
72    type Unvisited_Files_Record;
73    type Unvisited_Files_Access is access Unvisited_Files_Record;
74    type Unvisited_Files_Record is record
75       File : File_Reference;
76       Next : Unvisited_Files_Access;
77    end record;
78    --  A special list, in addition to File_HTable, that only stores
79    --  the files that haven't been visited so far. Note that the File
80    --  list points to some data in File_HTable, and thus should never be freed.
81
82    function Next (E : Declaration_Reference) return Declaration_Reference;
83    procedure Set_Next (E, Next : Declaration_Reference);
84    function  Get_Key (E : Declaration_Reference) return Cst_String_Access;
85    --  The subprograms above are used to instanciate the static
86    --  htable to store the entities that have been found in the application
87
88    package Entities_HTable is new GNAT.HTable.Static_HTable
89      (Header_Num => HTable_Headers,
90       Element    => Declaration_Record,
91       Elmt_Ptr   => Declaration_Reference,
92       Null_Ptr   => null,
93       Set_Next   => Set_Next,
94       Next       => Next,
95       Key        => Cst_String_Access,
96       Get_Key    => Get_Key,
97       Hash       => Hash,
98       Equal      => Equal);
99    --  A hash table to store all the entities defined in the
100    --  application. For each entity, we store a list of its reference
101    --  locations as well.
102    --  The keys in this htable should be created with Key_From_Ref,
103    --  and are the file, line and column of the declaration, which are
104    --  unique for every entity.
105
106    Entities_Count : Natural := 0;
107    --  Number of entities in Entities_HTable. This is used in the end
108    --  when sorting the table.
109
110    Longest_File_Name_In_Table : Natural := 0;
111    Unvisited_Files            : Unvisited_Files_Access := null;
112    Directories                : Project_File_Ptr;
113    Default_Match              : Boolean := False;
114    --  The above need commenting ???
115
116    function Parse_Gnatls_Src return String;
117    --  Return the standard source directories (taking into account the
118    --  ADA_INCLUDE_PATH environment variable, if Osint.Add_Default_Search_Dirs
119    --  was called first).
120
121    function Parse_Gnatls_Obj return String;
122    --  Return the standard object directories (taking into account the
123    --  ADA_OBJECTS_PATH environment variable).
124
125    function Key_From_Ref
126      (File_Ref  : File_Reference;
127       Line      : Natural;
128       Column    : Natural)
129       return      String;
130    --  Return a key for the symbol declared at File_Ref, Line,
131    --  Column. This key should be used for lookup in Entity_HTable
132
133    function Is_Less_Than (Decl1, Decl2 : Declaration_Reference) return Boolean;
134    --  Compare two declarations (the comparison is case-insensitive)
135
136    function Is_Less_Than (Ref1, Ref2 : Reference) return Boolean;
137    --  Compare two references
138
139    procedure Store_References
140      (Decl            : Declaration_Reference;
141       Get_Writes      : Boolean := False;
142       Get_Reads       : Boolean := False;
143       Get_Bodies      : Boolean := False;
144       Get_Declaration : Boolean := False;
145       Arr             : in out Reference_Array;
146       Index           : in out Natural);
147    --  Store in Arr, starting at Index, all the references to Decl. The Get_*
148    --  parameters can be used to indicate which references should be stored.
149    --  Constraint_Error will be raised if Arr is not big enough.
150
151    procedure Sort (Arr : in out Reference_Array);
152    --  Sort an array of references (Arr'First must be 1)
153
154    --------------
155    -- Set_Next --
156    --------------
157
158    procedure Set_Next (E : File_Reference; Next : File_Reference) is
159    begin
160       E.Next := Next;
161    end Set_Next;
162
163    procedure Set_Next
164      (E : Declaration_Reference; Next : Declaration_Reference) is
165    begin
166       E.Next := Next;
167    end Set_Next;
168
169    -------------
170    -- Get_Key --
171    -------------
172
173    function Get_Key (E : File_Reference) return Cst_String_Access is
174    begin
175       return E.File;
176    end Get_Key;
177
178    function Get_Key (E : Declaration_Reference) return Cst_String_Access is
179    begin
180       return E.Key;
181    end Get_Key;
182
183    ----------
184    -- Hash --
185    ----------
186
187    function Hash (F : Cst_String_Access) return HTable_Headers is
188       function H is new GNAT.HTable.Hash (HTable_Headers);
189
190    begin
191       return H (F.all);
192    end Hash;
193
194    -----------
195    -- Equal --
196    -----------
197
198    function Equal (F1, F2 : Cst_String_Access) return Boolean is
199    begin
200       return F1.all = F2.all;
201    end Equal;
202
203    ------------------
204    -- Key_From_Ref --
205    ------------------
206
207    function Key_From_Ref
208      (File_Ref : File_Reference;
209       Line     : Natural;
210       Column   : Natural)
211       return     String
212    is
213    begin
214       return File_Ref.File.all & Natural'Image (Line) & Natural'Image (Column);
215    end Key_From_Ref;
216
217    ---------------------
218    -- Add_Declaration --
219    ---------------------
220
221    function Add_Declaration
222      (File_Ref     : File_Reference;
223       Symbol       : String;
224       Line         : Natural;
225       Column       : Natural;
226       Decl_Type    : Character;
227       Remove_Only  : Boolean := False;
228       Symbol_Match : Boolean := True)
229       return         Declaration_Reference
230    is
231       procedure Unchecked_Free is new Ada.Unchecked_Deallocation
232         (Declaration_Record, Declaration_Reference);
233
234       Key : aliased constant String := Key_From_Ref (File_Ref, Line, Column);
235
236       New_Decl : Declaration_Reference :=
237                    Entities_HTable.Get (Key'Unchecked_Access);
238
239       Is_Parameter : Boolean := False;
240
241    begin
242       --  Insert the Declaration in the table. There might already be a
243       --  declaration in the table if the entity is a parameter, so we
244       --  need to check that first.
245
246       if New_Decl /= null and then New_Decl.Symbol_Length = 0 then
247          Is_Parameter := New_Decl.Is_Parameter;
248          Entities_HTable.Remove (Key'Unrestricted_Access);
249          Entities_Count := Entities_Count - 1;
250          Free (New_Decl.Key);
251          Unchecked_Free (New_Decl);
252          New_Decl := null;
253       end if;
254
255       --  The declaration might also already be there for parent types. In
256       --  this case, we should keep the entry, since some other entries are
257       --  pointing to it.
258
259       if New_Decl = null
260         and then not Remove_Only
261       then
262          New_Decl :=
263            new Declaration_Record'
264              (Symbol_Length => Symbol'Length,
265               Symbol        => Symbol,
266               Key           => new String'(Key),
267               Decl          => new Reference_Record'
268                                      (File          => File_Ref,
269                                       Line          => Line,
270                                       Column        => Column,
271                                       Source_Line   => null,
272                                       Next          => null),
273               Is_Parameter  => Is_Parameter,
274               Decl_Type     => Decl_Type,
275               Body_Ref      => null,
276               Ref_Ref       => null,
277               Modif_Ref     => null,
278               Match         => Symbol_Match
279                                  and then
280                                    (Default_Match
281                                      or else Match (File_Ref, Line, Column)),
282               Par_Symbol    => null,
283               Next          => null);
284
285          Entities_HTable.Set (New_Decl);
286          Entities_Count := Entities_Count + 1;
287
288          if New_Decl.Match then
289             Longest_File_Name_In_Table :=
290               Natural'Max (File_Ref.File'Length, Longest_File_Name_In_Table);
291          end if;
292
293       elsif New_Decl /= null
294         and then not New_Decl.Match
295       then
296          New_Decl.Match := Default_Match
297            or else Match (File_Ref, Line, Column);
298       end if;
299
300       return New_Decl;
301    end Add_Declaration;
302
303    ----------------------
304    -- Add_To_Xref_File --
305    ----------------------
306
307    function Add_To_Xref_File
308      (File_Name       : String;
309       Visited         : Boolean := True;
310       Emit_Warning    : Boolean := False;
311       Gnatchop_File   : String  := "";
312       Gnatchop_Offset : Integer := 0) return File_Reference
313    is
314       Base    : aliased constant String := Base_Name (File_Name);
315       Dir     : constant String := Dir_Name (File_Name);
316       Dir_Acc : GNAT.OS_Lib.String_Access   := null;
317       Ref     : File_Reference;
318
319    begin
320       --  Do we have a directory name as well?
321
322       if File_Name /= Base then
323          Dir_Acc := new String'(Dir);
324       end if;
325
326       Ref := File_HTable.Get (Base'Unchecked_Access);
327       if Ref = null then
328          Ref := new File_Record'
329            (File            => new String'(Base),
330             Dir             => Dir_Acc,
331             Lines           => null,
332             Visited         => Visited,
333             Emit_Warning    => Emit_Warning,
334             Gnatchop_File   => new String'(Gnatchop_File),
335             Gnatchop_Offset => Gnatchop_Offset,
336             Next            => null);
337          File_HTable.Set (Ref);
338
339          if not Visited then
340
341             --  Keep a separate list for faster access
342
343             Set_Unvisited (Ref);
344          end if;
345       end if;
346       return Ref;
347    end Add_To_Xref_File;
348
349    --------------
350    -- Add_Line --
351    --------------
352
353    procedure Add_Line
354      (File   : File_Reference;
355       Line   : Natural;
356       Column : Natural)
357    is
358    begin
359       File.Lines := new Ref_In_File'(Line   => Line,
360                                      Column => Column,
361                                      Next   => File.Lines);
362    end Add_Line;
363
364    ----------------
365    -- Add_Parent --
366    ----------------
367
368    procedure Add_Parent
369      (Declaration : in out Declaration_Reference;
370       Symbol      : String;
371       Line        : Natural;
372       Column      : Natural;
373       File_Ref    : File_Reference)
374    is
375    begin
376       Declaration.Par_Symbol :=
377         Add_Declaration
378           (File_Ref, Symbol, Line, Column,
379            Decl_Type    => ' ',
380            Symbol_Match => False);
381    end Add_Parent;
382
383    -------------------
384    -- Add_Reference --
385    -------------------
386
387    procedure Add_Reference
388      (Declaration   : Declaration_Reference;
389       File_Ref      : File_Reference;
390       Line          : Natural;
391       Column        : Natural;
392       Ref_Type      : Character;
393       Labels_As_Ref : Boolean)
394    is
395       New_Ref : Reference;
396
397    begin
398       case Ref_Type is
399          when 'b' | 'c' | 'm' | 'r' | 'i' | ' ' | 'x' =>
400             null;
401
402          when 'l' | 'w' =>
403             if not Labels_As_Ref then
404                return;
405             end if;
406
407          when '=' | '<' | '>' | '^' =>
408
409             --  Create a dummy declaration in the table to report it as a
410             --  parameter. Note that the current declaration for the subprogram
411             --  comes before the declaration of the parameter.
412
413             declare
414                Key      : constant String :=
415                             Key_From_Ref (File_Ref, Line, Column);
416                New_Decl : Declaration_Reference;
417
418             begin
419                New_Decl := new Declaration_Record'
420                  (Symbol_Length => 0,
421                   Symbol        => "",
422                   Key           => new String'(Key),
423                   Decl          => null,
424                   Is_Parameter  => True,
425                   Decl_Type     => ' ',
426                   Body_Ref      => null,
427                   Ref_Ref       => null,
428                   Modif_Ref     => null,
429                   Match         => False,
430                   Par_Symbol    => null,
431                   Next          => null);
432                Entities_HTable.Set (New_Decl);
433                Entities_Count := Entities_Count + 1;
434             end;
435
436          when 'e' | 'z' | 't' | 'p' | 'P' | 'k' | 'd' =>
437             return;
438
439          when others    =>
440             Ada.Text_IO.Put_Line ("Unknown reference type: " & Ref_Type);
441             return;
442       end case;
443
444       New_Ref := new Reference_Record'
445         (File        => File_Ref,
446          Line        => Line,
447          Column      => Column,
448          Source_Line => null,
449          Next        => null);
450
451       --  We can insert the reference in the list directly, since all
452       --  the references will appear only once in the ALI file
453       --  corresponding to the file where they are referenced.
454       --  This saves a lot of time compared to checking the list to check
455       --  if it exists.
456
457       case Ref_Type is
458          when 'b' | 'c' =>
459             New_Ref.Next          := Declaration.Body_Ref;
460             Declaration.Body_Ref  := New_Ref;
461
462          when 'r' | 'i' | 'l' | ' ' | 'x' | 'w' =>
463             New_Ref.Next          := Declaration.Ref_Ref;
464             Declaration.Ref_Ref   := New_Ref;
465
466          when 'm' =>
467             New_Ref.Next          := Declaration.Modif_Ref;
468             Declaration.Modif_Ref := New_Ref;
469
470          when others =>
471             null;
472       end case;
473
474       if not Declaration.Match then
475          Declaration.Match := Match (File_Ref, Line, Column);
476       end if;
477
478       if Declaration.Match then
479          Longest_File_Name_In_Table :=
480            Natural'Max (File_Ref.File'Length, Longest_File_Name_In_Table);
481       end if;
482    end Add_Reference;
483
484    -------------------
485    -- ALI_File_Name --
486    -------------------
487
488    function ALI_File_Name (Ada_File_Name : String) return String is
489
490       --  ??? Should ideally be based on the naming scheme defined in
491       --  project files.
492
493       Index : constant Natural :=
494                 Ada.Strings.Fixed.Index
495                   (Ada_File_Name, ".", Going => Ada.Strings.Backward);
496
497    begin
498       if Index /= 0 then
499          return Ada_File_Name (Ada_File_Name'First .. Index) & "ali";
500       else
501          return Ada_File_Name & ".ali";
502       end if;
503    end ALI_File_Name;
504
505    ------------------
506    -- Is_Less_Than --
507    ------------------
508
509    function Is_Less_Than (Ref1, Ref2 : Reference) return Boolean is
510    begin
511       if Ref1 = null then
512          return False;
513       elsif Ref2 = null then
514          return True;
515       end if;
516
517       if Ref1.File.File.all < Ref2.File.File.all then
518          return True;
519
520       elsif Ref1.File.File.all = Ref2.File.File.all then
521          return (Ref1.Line < Ref2.Line
522                  or else (Ref1.Line = Ref2.Line
523                           and then Ref1.Column < Ref2.Column));
524       end if;
525
526       return False;
527    end Is_Less_Than;
528
529    ------------------
530    -- Is_Less_Than --
531    ------------------
532
533    function Is_Less_Than (Decl1, Decl2 : Declaration_Reference) return Boolean
534    is
535       --  We cannot store the data case-insensitive in the table,
536       --  since we wouldn't be able to find the right casing for the
537       --  display later on.
538
539       S1 : constant String := To_Lower (Decl1.Symbol);
540       S2 : constant String := To_Lower (Decl2.Symbol);
541
542    begin
543       if S1 < S2 then
544          return True;
545       elsif S1 > S2 then
546          return False;
547       end if;
548
549       return Decl1.Key.all < Decl2.Key.all;
550    end Is_Less_Than;
551
552    -------------------------
553    -- Create_Project_File --
554    -------------------------
555
556    procedure Create_Project_File (Name : String) is
557       Obj_Dir     : Unbounded_String := Null_Unbounded_String;
558       Src_Dir     : Unbounded_String := Null_Unbounded_String;
559       Build_Dir   : GNAT.OS_Lib.String_Access := new String'("");
560
561       F           : File_Descriptor;
562       Len         : Positive;
563       File_Name   : aliased String := Name & ASCII.NUL;
564
565    begin
566       --  Read the size of the file
567
568       F := Open_Read (File_Name'Address, Text);
569
570       --  Project file not found
571
572       if F /= Invalid_FD then
573          Len := Positive (File_Length (F));
574
575          declare
576             Buffer : String (1 .. Len);
577             Index  : Positive := Buffer'First;
578             Last   : Positive;
579
580          begin
581             Len := Read (F, Buffer'Address, Len);
582             Close (F);
583
584             --  First, look for Build_Dir, since all the source and object
585             --  path are relative to it.
586
587             while Index <= Buffer'Last loop
588
589                --  Find the end of line
590
591                Last := Index;
592                while Last <= Buffer'Last
593                  and then Buffer (Last) /= ASCII.LF
594                  and then Buffer (Last) /= ASCII.CR
595                loop
596                   Last := Last + 1;
597                end loop;
598
599                if Index <= Buffer'Last - 9
600                  and then Buffer (Index .. Index + 9) = "build_dir="
601                then
602                   Index := Index + 10;
603                   while Index <= Last
604                     and then (Buffer (Index) = ' '
605                               or else Buffer (Index) = ASCII.HT)
606                   loop
607                      Index := Index + 1;
608                   end loop;
609
610                   Free (Build_Dir);
611                   Build_Dir := new String'(Buffer (Index .. Last - 1));
612                end if;
613
614                Index := Last + 1;
615
616                --  In case we had a ASCII.CR/ASCII.LF end of line, skip the
617                --  remaining symbol
618
619                if Index <= Buffer'Last
620                  and then Buffer (Index) = ASCII.LF
621                then
622                   Index := Index + 1;
623                end if;
624             end loop;
625
626             --  Now parse the source and object paths
627
628             Index := Buffer'First;
629             while Index <= Buffer'Last loop
630
631                --  Find the end of line
632
633                Last := Index;
634                while Last <= Buffer'Last
635                  and then Buffer (Last) /= ASCII.LF
636                  and then Buffer (Last) /= ASCII.CR
637                loop
638                   Last := Last + 1;
639                end loop;
640
641                if Index <= Buffer'Last - 7
642                  and then Buffer (Index .. Index + 7) = "src_dir="
643                then
644                   Append (Src_Dir, Normalize_Pathname
645                           (Name      => Ada.Strings.Fixed.Trim
646                            (Buffer (Index + 8 .. Last - 1), Ada.Strings.Both),
647                            Directory => Build_Dir.all) & Path_Separator);
648
649                elsif Index <= Buffer'Last - 7
650                  and then Buffer (Index .. Index + 7) = "obj_dir="
651                then
652                   Append (Obj_Dir, Normalize_Pathname
653                           (Name      => Ada.Strings.Fixed.Trim
654                            (Buffer (Index + 8 .. Last - 1), Ada.Strings.Both),
655                            Directory => Build_Dir.all) & Path_Separator);
656                end if;
657
658                --  In case we had a ASCII.CR/ASCII.LF end of line, skip the
659                --  remaining symbol
660                Index := Last + 1;
661
662                if Index <= Buffer'Last
663                  and then Buffer (Index) = ASCII.LF
664                then
665                   Index := Index + 1;
666                end if;
667             end loop;
668          end;
669       end if;
670
671       Osint.Add_Default_Search_Dirs;
672
673       declare
674          Src : constant String := Parse_Gnatls_Src;
675          Obj : constant String := Parse_Gnatls_Obj;
676
677       begin
678          Directories := new Project_File'
679            (Src_Dir_Length     => Length (Src_Dir) + Src'Length,
680             Obj_Dir_Length     => Length (Obj_Dir) + Obj'Length,
681             Src_Dir            => To_String (Src_Dir) & Src,
682             Obj_Dir            => To_String (Obj_Dir) & Obj,
683             Src_Dir_Index      => 1,
684             Obj_Dir_Index      => 1,
685             Last_Obj_Dir_Start => 0);
686       end;
687
688       Free (Build_Dir);
689    end Create_Project_File;
690
691    ---------------------
692    -- Current_Obj_Dir --
693    ---------------------
694
695    function Current_Obj_Dir return String is
696    begin
697       return Directories.Obj_Dir
698         (Directories.Last_Obj_Dir_Start .. Directories.Obj_Dir_Index - 2);
699    end Current_Obj_Dir;
700
701    ----------------
702    -- Get_Column --
703    ----------------
704
705    function Get_Column (Decl : Declaration_Reference) return String is
706    begin
707       return Ada.Strings.Fixed.Trim (Natural'Image (Decl.Decl.Column),
708                                      Ada.Strings.Left);
709    end Get_Column;
710
711    function Get_Column (Ref : Reference) return String is
712    begin
713       return Ada.Strings.Fixed.Trim (Natural'Image (Ref.Column),
714                                      Ada.Strings.Left);
715    end Get_Column;
716
717    ---------------------
718    -- Get_Declaration --
719    ---------------------
720
721    function Get_Declaration
722      (File_Ref : File_Reference;
723       Line     : Natural;
724       Column   : Natural)
725       return     Declaration_Reference
726    is
727       Key : aliased constant String := Key_From_Ref (File_Ref, Line, Column);
728
729    begin
730       return Entities_HTable.Get (Key'Unchecked_Access);
731    end Get_Declaration;
732
733    ----------------------
734    -- Get_Emit_Warning --
735    ----------------------
736
737    function Get_Emit_Warning (File : File_Reference) return Boolean is
738    begin
739       return File.Emit_Warning;
740    end Get_Emit_Warning;
741
742    --------------
743    -- Get_File --
744    --------------
745
746    function Get_File
747      (Decl     : Declaration_Reference;
748       With_Dir : Boolean := False) return String
749    is
750    begin
751       return Get_File (Decl.Decl.File, With_Dir);
752    end Get_File;
753
754    function Get_File
755      (Ref      : Reference;
756       With_Dir : Boolean := False) return String
757    is
758    begin
759       return Get_File (Ref.File, With_Dir);
760    end Get_File;
761
762    function Get_File
763      (File     : File_Reference;
764       With_Dir : Boolean := False;
765       Strip    : Natural    := 0) return String
766    is
767       Tmp : GNAT.OS_Lib.String_Access;
768
769       function Internal_Strip (Full_Name : String) return String;
770       --  Internal function to process the Strip parameter
771
772       --------------------
773       -- Internal_Strip --
774       --------------------
775
776       function Internal_Strip (Full_Name : String) return String is
777          Unit_End        : Natural;
778          Extension_Start : Natural;
779          S               : Natural;
780
781       begin
782          if Strip = 0 then
783             return Full_Name;
784          end if;
785
786          --  Isolate the file extension
787
788          Extension_Start := Full_Name'Last;
789          while Extension_Start >= Full_Name'First
790            and then Full_Name (Extension_Start) /= '.'
791          loop
792             Extension_Start := Extension_Start - 1;
793          end loop;
794
795          --  Strip the right number of subunit_names
796
797          S := Strip;
798          Unit_End := Extension_Start - 1;
799          while Unit_End >= Full_Name'First
800            and then S > 0
801          loop
802             if Full_Name (Unit_End) = '-' then
803                S := S - 1;
804             end if;
805
806             Unit_End := Unit_End - 1;
807          end loop;
808
809          if Unit_End < Full_Name'First then
810             return "";
811          else
812             return Full_Name (Full_Name'First .. Unit_End)
813               & Full_Name (Extension_Start .. Full_Name'Last);
814          end if;
815       end Internal_Strip;
816
817    --  Start of processing for Get_File;
818
819    begin
820       --  If we do not want the full path name
821
822       if not With_Dir then
823          return Internal_Strip (File.File.all);
824       end if;
825
826       if File.Dir = null then
827          if Ada.Strings.Fixed.Tail (File.File.all, 3) = "ali" then
828             Tmp := Locate_Regular_File
829               (Internal_Strip (File.File.all), Directories.Obj_Dir);
830          else
831             Tmp := Locate_Regular_File
832               (File.File.all, Directories.Src_Dir);
833          end if;
834
835          if Tmp = null then
836             File.Dir := new String'("");
837          else
838             File.Dir := new String'(Dir_Name (Tmp.all));
839             Free (Tmp);
840          end if;
841       end if;
842
843       return Internal_Strip (File.Dir.all & File.File.all);
844    end Get_File;
845
846    ------------------
847    -- Get_File_Ref --
848    ------------------
849
850    function Get_File_Ref (Ref : Reference) return File_Reference is
851    begin
852       return Ref.File;
853    end Get_File_Ref;
854
855    -----------------------
856    -- Get_Gnatchop_File --
857    -----------------------
858
859    function Get_Gnatchop_File
860      (File     : File_Reference;
861       With_Dir : Boolean := False)
862       return     String
863    is
864    begin
865       if File.Gnatchop_File.all = "" then
866          return Get_File (File, With_Dir);
867       else
868          return File.Gnatchop_File.all;
869       end if;
870    end Get_Gnatchop_File;
871
872    function Get_Gnatchop_File
873      (Ref      : Reference;
874       With_Dir : Boolean := False)
875       return     String
876    is
877    begin
878       return Get_Gnatchop_File (Ref.File, With_Dir);
879    end Get_Gnatchop_File;
880
881    function Get_Gnatchop_File
882      (Decl     : Declaration_Reference;
883       With_Dir : Boolean := False)
884       return     String
885    is
886    begin
887       return Get_Gnatchop_File (Decl.Decl.File, With_Dir);
888    end Get_Gnatchop_File;
889
890    --------------
891    -- Get_Line --
892    --------------
893
894    function Get_Line (Decl : Declaration_Reference) return String is
895    begin
896       return Ada.Strings.Fixed.Trim (Natural'Image (Decl.Decl.Line),
897                                      Ada.Strings.Left);
898    end Get_Line;
899
900    function Get_Line (Ref : Reference) return String is
901    begin
902       return Ada.Strings.Fixed.Trim (Natural'Image (Ref.Line),
903                                      Ada.Strings.Left);
904    end Get_Line;
905
906    ----------------
907    -- Get_Parent --
908    ----------------
909
910    function Get_Parent
911      (Decl : Declaration_Reference)
912       return Declaration_Reference
913    is
914    begin
915       return Decl.Par_Symbol;
916    end Get_Parent;
917
918    ---------------------
919    -- Get_Source_Line --
920    ---------------------
921
922    function Get_Source_Line (Ref : Reference) return String is
923    begin
924       if Ref.Source_Line /= null then
925          return Ref.Source_Line.all;
926       else
927          return "";
928       end if;
929    end Get_Source_Line;
930
931    function Get_Source_Line (Decl : Declaration_Reference) return String is
932    begin
933       if Decl.Decl.Source_Line /= null then
934          return Decl.Decl.Source_Line.all;
935       else
936          return "";
937       end if;
938    end Get_Source_Line;
939
940    ----------------
941    -- Get_Symbol --
942    ----------------
943
944    function Get_Symbol (Decl : Declaration_Reference) return String is
945    begin
946       return Decl.Symbol;
947    end Get_Symbol;
948
949    --------------
950    -- Get_Type --
951    --------------
952
953    function Get_Type (Decl : Declaration_Reference) return Character is
954    begin
955       return Decl.Decl_Type;
956    end Get_Type;
957
958    ----------
959    -- Sort --
960    ----------
961
962    procedure Sort (Arr : in out Reference_Array) is
963       Tmp : Reference;
964
965       function Lt (Op1, Op2 : Natural) return Boolean;
966       procedure Move (From, To : Natural);
967       --  See GNAT.Heap_Sort_G
968
969       --------
970       -- Lt --
971       --------
972
973       function Lt (Op1, Op2 : Natural) return Boolean is
974       begin
975          if Op1 = 0 then
976             return Is_Less_Than (Tmp, Arr (Op2));
977          elsif Op2 = 0 then
978             return Is_Less_Than (Arr (Op1), Tmp);
979          else
980             return Is_Less_Than (Arr (Op1), Arr (Op2));
981          end if;
982       end Lt;
983
984       ----------
985       -- Move --
986       ----------
987
988       procedure Move (From, To : Natural) is
989       begin
990          if To = 0 then
991             Tmp := Arr (From);
992          elsif From = 0 then
993             Arr (To) := Tmp;
994          else
995             Arr (To) := Arr (From);
996          end if;
997       end Move;
998
999       package Ref_Sort is new GNAT.Heap_Sort_G (Move, Lt);
1000
1001    --  Start of processing for Sort
1002
1003    begin
1004       Ref_Sort.Sort (Arr'Last);
1005    end Sort;
1006
1007    -----------------------
1008    -- Grep_Source_Files --
1009    -----------------------
1010
1011    procedure Grep_Source_Files is
1012       Length       : Natural := 0;
1013       Decl         : Declaration_Reference := Entities_HTable.Get_First;
1014       Arr          : Reference_Array_Access;
1015       Index        : Natural;
1016       End_Index    : Natural;
1017       Current_File : File_Reference;
1018       Current_Line : Cst_String_Access;
1019       Buffer       : GNAT.OS_Lib.String_Access;
1020       Ref          : Reference;
1021       Line         : Natural;
1022
1023    begin
1024       --  Create a temporary array, where all references will be
1025       --  sorted by files. This way, we only have to read the source
1026       --  files once.
1027
1028       while Decl /= null loop
1029
1030          --  Add 1 for the declaration itself
1031
1032          Length := Length + References_Count (Decl, True, True, True) + 1;
1033          Decl := Entities_HTable.Get_Next;
1034       end loop;
1035
1036       Arr := new Reference_Array (1 .. Length);
1037       Index := Arr'First;
1038
1039       Decl := Entities_HTable.Get_First;
1040       while Decl /= null loop
1041          Store_References (Decl, True, True, True, True, Arr.all, Index);
1042          Decl := Entities_HTable.Get_Next;
1043       end loop;
1044
1045       Sort (Arr.all);
1046
1047       --  Now traverse the whole array and find the appropriate source
1048       --  lines.
1049
1050       for R in Arr'Range loop
1051          Ref := Arr (R);
1052
1053          if Ref.File /= Current_File then
1054             Free (Buffer);
1055             begin
1056                Read_File (Get_File (Ref.File, With_Dir => True), Buffer);
1057                End_Index := Buffer'First - 1;
1058                Line := 0;
1059             exception
1060                when Ada.Text_IO.Name_Error | Ada.Text_IO.End_Error =>
1061                   Line := Natural'Last;
1062             end;
1063             Current_File := Ref.File;
1064          end if;
1065
1066          if Ref.Line > Line then
1067
1068             --  Do not free Current_Line, it is referenced by the last
1069             --  Ref we processed.
1070
1071             loop
1072                Index := End_Index + 1;
1073
1074                loop
1075                   End_Index := End_Index + 1;
1076                   exit when End_Index > Buffer'Last
1077                     or else Buffer (End_Index) = ASCII.LF;
1078                end loop;
1079
1080                --  Skip spaces at beginning of line
1081
1082                while Index < End_Index and then
1083                  (Buffer (Index) = ' ' or else Buffer (Index) = ASCII.HT)
1084                loop
1085                   Index := Index + 1;
1086                end loop;
1087
1088                Line := Line + 1;
1089                exit when Ref.Line = Line;
1090             end loop;
1091
1092             Current_Line := new String'(Buffer (Index .. End_Index - 1));
1093          end if;
1094
1095          Ref.Source_Line := Current_Line;
1096       end loop;
1097
1098       Free (Buffer);
1099       Free (Arr);
1100    end Grep_Source_Files;
1101
1102    ---------------
1103    -- Read_File --
1104    ---------------
1105
1106    procedure Read_File
1107      (File_Name : String;
1108       Contents  : out GNAT.OS_Lib.String_Access)
1109    is
1110       Name_0 : constant String := File_Name & ASCII.NUL;
1111       FD     : constant File_Descriptor := Open_Read (Name_0'Address, Binary);
1112       Length : Natural;
1113
1114    begin
1115       if FD = Invalid_FD then
1116          raise Ada.Text_IO.Name_Error;
1117       end if;
1118
1119       --  Include room for EOF char
1120
1121       Length := Natural (File_Length (FD));
1122
1123       declare
1124          Buffer    : String (1 .. Length + 1);
1125          This_Read : Integer;
1126          Read_Ptr  : Natural := 1;
1127
1128       begin
1129          loop
1130             This_Read := Read (FD,
1131                                A => Buffer (Read_Ptr)'Address,
1132                                N => Length + 1 - Read_Ptr);
1133             Read_Ptr := Read_Ptr + Integer'Max (This_Read, 0);
1134             exit when This_Read <= 0;
1135          end loop;
1136
1137          Buffer (Read_Ptr) := EOF;
1138          Contents := new String'(Buffer (1 .. Read_Ptr));
1139
1140          --  Things are not simple on VMS due to the plethora of file types
1141          --  and organizations. It seems clear that there shouldn't be more
1142          --  bytes read than are contained in the file though.
1143
1144          if (Hostparm.OpenVMS and then Read_Ptr > Length + 1)
1145            or else (not Hostparm.OpenVMS and then Read_Ptr /= Length + 1)
1146          then
1147             raise Ada.Text_IO.End_Error;
1148          end if;
1149
1150          Close (FD);
1151       end;
1152    end Read_File;
1153
1154    -----------------------
1155    -- Longest_File_Name --
1156    -----------------------
1157
1158    function Longest_File_Name return Natural is
1159    begin
1160       return Longest_File_Name_In_Table;
1161    end Longest_File_Name;
1162
1163    -----------
1164    -- Match --
1165    -----------
1166
1167    function Match
1168      (File   : File_Reference;
1169       Line   : Natural;
1170       Column : Natural)
1171       return   Boolean
1172    is
1173       Ref : Ref_In_File_Ptr := File.Lines;
1174
1175    begin
1176       while Ref /= null loop
1177          if (Ref.Line = 0 or else Ref.Line = Line)
1178            and then (Ref.Column = 0 or else Ref.Column = Column)
1179          then
1180             return True;
1181          end if;
1182
1183          Ref := Ref.Next;
1184       end loop;
1185
1186       return False;
1187    end Match;
1188
1189    -----------
1190    -- Match --
1191    -----------
1192
1193    function Match (Decl : Declaration_Reference) return Boolean is
1194    begin
1195       return Decl.Match;
1196    end Match;
1197
1198    ----------
1199    -- Next --
1200    ----------
1201
1202    function Next (E : File_Reference) return File_Reference is
1203    begin
1204       return E.Next;
1205    end Next;
1206
1207    function Next (E : Declaration_Reference) return Declaration_Reference is
1208    begin
1209       return E.Next;
1210    end Next;
1211
1212    ------------------
1213    -- Next_Obj_Dir --
1214    ------------------
1215
1216    function Next_Obj_Dir return String is
1217       First : constant Integer := Directories.Obj_Dir_Index;
1218       Last  : Integer;
1219
1220    begin
1221       Last := Directories.Obj_Dir_Index;
1222
1223       if Last > Directories.Obj_Dir_Length then
1224          return String'(1 .. 0 => ' ');
1225       end if;
1226
1227       while Directories.Obj_Dir (Last) /= Path_Separator loop
1228          Last := Last + 1;
1229       end loop;
1230
1231       Directories.Obj_Dir_Index := Last + 1;
1232       Directories.Last_Obj_Dir_Start := First;
1233       return Directories.Obj_Dir (First .. Last - 1);
1234    end Next_Obj_Dir;
1235
1236    -------------------------
1237    -- Next_Unvisited_File --
1238    -------------------------
1239
1240    function Next_Unvisited_File return File_Reference is
1241       procedure Unchecked_Free is new Ada.Unchecked_Deallocation
1242         (Unvisited_Files_Record, Unvisited_Files_Access);
1243
1244       Ref : File_Reference;
1245       Tmp : Unvisited_Files_Access;
1246
1247    begin
1248       if Unvisited_Files = null then
1249          return Empty_File;
1250       else
1251          Tmp := Unvisited_Files;
1252          Ref := Unvisited_Files.File;
1253          Unvisited_Files := Unvisited_Files.Next;
1254          Unchecked_Free (Tmp);
1255          return Ref;
1256       end if;
1257    end Next_Unvisited_File;
1258
1259    ----------------------
1260    -- Parse_Gnatls_Src --
1261    ----------------------
1262
1263    function Parse_Gnatls_Src return String is
1264       Length : Natural;
1265
1266    begin
1267       Length := 0;
1268       for J in 1 .. Osint.Nb_Dir_In_Src_Search_Path loop
1269          if Osint.Dir_In_Src_Search_Path (J)'Length = 0 then
1270             Length := Length + 2;
1271          else
1272             Length := Length + Osint.Dir_In_Src_Search_Path (J)'Length + 1;
1273          end if;
1274       end loop;
1275
1276       declare
1277          Result : String (1 .. Length);
1278          L      : Natural;
1279
1280       begin
1281          L := Result'First;
1282          for J in 1 .. Osint.Nb_Dir_In_Src_Search_Path loop
1283             if Osint.Dir_In_Src_Search_Path (J)'Length = 0 then
1284                Result (L .. L + 1) := "." & Path_Separator;
1285                L := L + 2;
1286
1287             else
1288                Result (L .. L + Osint.Dir_In_Src_Search_Path (J)'Length - 1) :=
1289                  Osint.Dir_In_Src_Search_Path (J).all;
1290                L := L + Osint.Dir_In_Src_Search_Path (J)'Length;
1291                Result (L) := Path_Separator;
1292                L := L + 1;
1293             end if;
1294          end loop;
1295
1296          return Result;
1297       end;
1298    end Parse_Gnatls_Src;
1299
1300    ----------------------
1301    -- Parse_Gnatls_Obj --
1302    ----------------------
1303
1304    function Parse_Gnatls_Obj return String is
1305       Length : Natural;
1306
1307    begin
1308       Length := 0;
1309       for J in 1 .. Osint.Nb_Dir_In_Obj_Search_Path loop
1310          if Osint.Dir_In_Obj_Search_Path (J)'Length = 0 then
1311             Length := Length + 2;
1312          else
1313             Length := Length + Osint.Dir_In_Obj_Search_Path (J)'Length + 1;
1314          end if;
1315       end loop;
1316
1317       declare
1318          Result : String (1 .. Length);
1319          L      : Natural;
1320
1321       begin
1322          L := Result'First;
1323          for J in 1 .. Osint.Nb_Dir_In_Obj_Search_Path loop
1324             if Osint.Dir_In_Obj_Search_Path (J)'Length = 0 then
1325                Result (L .. L + 1) := "." & Path_Separator;
1326                L := L + 2;
1327             else
1328                Result (L .. L + Osint.Dir_In_Obj_Search_Path (J)'Length - 1) :=
1329                  Osint.Dir_In_Obj_Search_Path (J).all;
1330                L := L + Osint.Dir_In_Obj_Search_Path (J)'Length;
1331                Result (L) := Path_Separator;
1332                L := L + 1;
1333             end if;
1334          end loop;
1335
1336          return Result;
1337       end;
1338    end Parse_Gnatls_Obj;
1339
1340    -------------------
1341    -- Reset_Obj_Dir --
1342    -------------------
1343
1344    procedure Reset_Obj_Dir is
1345    begin
1346       Directories.Obj_Dir_Index := 1;
1347    end Reset_Obj_Dir;
1348
1349    -----------------------
1350    -- Set_Default_Match --
1351    -----------------------
1352
1353    procedure Set_Default_Match (Value : Boolean) is
1354    begin
1355       Default_Match := Value;
1356    end Set_Default_Match;
1357
1358    ----------
1359    -- Free --
1360    ----------
1361
1362    procedure Free (Str : in out Cst_String_Access) is
1363       function Convert is new Ada.Unchecked_Conversion
1364         (Cst_String_Access, GNAT.OS_Lib.String_Access);
1365
1366       S : GNAT.OS_Lib.String_Access := Convert (Str);
1367
1368    begin
1369       Free (S);
1370       Str := null;
1371    end Free;
1372
1373    ---------------------
1374    -- Reset_Directory --
1375    ---------------------
1376
1377    procedure Reset_Directory (File : File_Reference) is
1378    begin
1379       Free (File.Dir);
1380    end Reset_Directory;
1381
1382    -------------------
1383    -- Set_Unvisited --
1384    -------------------
1385
1386    procedure Set_Unvisited (File_Ref : File_Reference) is
1387       F : constant String := Get_File (File_Ref, With_Dir => False);
1388
1389    begin
1390       File_Ref.Visited := False;
1391
1392       --  ??? Do not add a source file to the list. This is true at
1393       --  least for gnatxref, and probably for gnatfind as wel
1394
1395       if F'Length > 4
1396         and then F (F'Last - 3 .. F'Last) = ".ali"
1397       then
1398          Unvisited_Files := new Unvisited_Files_Record'
1399            (File => File_Ref,
1400             Next => Unvisited_Files);
1401       end if;
1402    end Set_Unvisited;
1403
1404    ----------------------
1405    -- Get_Declarations --
1406    ----------------------
1407
1408    function Get_Declarations
1409      (Sorted : Boolean := True)
1410       return   Declaration_Array_Access
1411    is
1412       Arr   : constant Declaration_Array_Access :=
1413                 new Declaration_Array (1 .. Entities_Count);
1414       Decl  : Declaration_Reference := Entities_HTable.Get_First;
1415       Index : Natural               := Arr'First;
1416       Tmp   : Declaration_Reference;
1417
1418       procedure Move (From : Natural; To : Natural);
1419       function Lt (Op1, Op2 : Natural) return Boolean;
1420       --  See GNAT.Heap_Sort_G
1421
1422       --------
1423       -- Lt --
1424       --------
1425
1426       function Lt (Op1, Op2 : Natural) return Boolean is
1427       begin
1428          if Op1 = 0 then
1429             return Is_Less_Than (Tmp, Arr (Op2));
1430          elsif Op2 = 0 then
1431             return Is_Less_Than (Arr (Op1), Tmp);
1432          else
1433             return Is_Less_Than (Arr (Op1), Arr (Op2));
1434          end if;
1435       end Lt;
1436
1437       ----------
1438       -- Move --
1439       ----------
1440
1441       procedure Move (From : Natural; To : Natural) is
1442       begin
1443          if To = 0 then
1444             Tmp := Arr (From);
1445          elsif From = 0 then
1446             Arr (To) := Tmp;
1447          else
1448             Arr (To) := Arr (From);
1449          end if;
1450       end Move;
1451
1452       package Decl_Sort is new GNAT.Heap_Sort_G (Move, Lt);
1453
1454    --  Start of processing for Get_Declarations
1455
1456    begin
1457       while Decl /= null loop
1458          Arr (Index) := Decl;
1459          Index := Index + 1;
1460          Decl := Entities_HTable.Get_Next;
1461       end loop;
1462
1463       if Sorted and then Arr'Length /= 0 then
1464          Decl_Sort.Sort (Entities_Count);
1465       end if;
1466
1467       return Arr;
1468    end Get_Declarations;
1469
1470    ----------------------
1471    -- References_Count --
1472    ----------------------
1473
1474    function References_Count
1475      (Decl       : Declaration_Reference;
1476       Get_Reads  : Boolean := False;
1477       Get_Writes : Boolean := False;
1478       Get_Bodies : Boolean := False)
1479       return       Natural
1480    is
1481       function List_Length (E : Reference) return Natural;
1482       --  Return the number of references in E
1483
1484       -----------------
1485       -- List_Length --
1486       -----------------
1487
1488       function List_Length (E : Reference) return Natural is
1489          L  : Natural := 0;
1490          E1 : Reference := E;
1491
1492       begin
1493          while E1 /= null loop
1494             L := L + 1;
1495             E1 := E1.Next;
1496          end loop;
1497
1498          return L;
1499       end List_Length;
1500
1501       Length : Natural := 0;
1502
1503    --  Start of processing for References_Count
1504
1505    begin
1506       if Get_Reads then
1507          Length := List_Length (Decl.Ref_Ref);
1508       end if;
1509
1510       if Get_Writes then
1511          Length := Length + List_Length (Decl.Modif_Ref);
1512       end if;
1513
1514       if Get_Bodies then
1515          Length := Length + List_Length (Decl.Body_Ref);
1516       end if;
1517
1518       return Length;
1519    end References_Count;
1520
1521    ----------------------
1522    -- Store_References --
1523    ----------------------
1524
1525    procedure Store_References
1526      (Decl            : Declaration_Reference;
1527       Get_Writes      : Boolean := False;
1528       Get_Reads       : Boolean := False;
1529       Get_Bodies      : Boolean := False;
1530       Get_Declaration : Boolean := False;
1531       Arr             : in out Reference_Array;
1532       Index           : in out Natural)
1533    is
1534       procedure Add (List : Reference);
1535       --  Add all the references in List to Arr
1536
1537       ---------
1538       -- Add --
1539       ---------
1540
1541       procedure Add (List : Reference) is
1542          E : Reference := List;
1543       begin
1544          while E /= null loop
1545             Arr (Index) := E;
1546             Index := Index + 1;
1547             E := E.Next;
1548          end loop;
1549       end Add;
1550
1551    --  Start of processing for Store_References
1552
1553    begin
1554       if Get_Declaration then
1555          Add (Decl.Decl);
1556       end if;
1557
1558       if Get_Reads then
1559          Add (Decl.Ref_Ref);
1560       end if;
1561
1562       if Get_Writes then
1563          Add (Decl.Modif_Ref);
1564       end if;
1565
1566       if Get_Bodies then
1567          Add (Decl.Body_Ref);
1568       end if;
1569    end Store_References;
1570
1571    --------------------
1572    -- Get_References --
1573    --------------------
1574
1575    function Get_References
1576      (Decl : Declaration_Reference;
1577       Get_Reads  : Boolean := False;
1578       Get_Writes : Boolean := False;
1579       Get_Bodies : Boolean := False)
1580       return       Reference_Array_Access
1581    is
1582       Length : constant Natural :=
1583                  References_Count (Decl, Get_Reads, Get_Writes, Get_Bodies);
1584
1585       Arr : constant Reference_Array_Access :=
1586               new Reference_Array (1 .. Length);
1587
1588       Index : Natural := Arr'First;
1589
1590    begin
1591       Store_References
1592         (Decl            => Decl,
1593          Get_Writes      => Get_Writes,
1594          Get_Reads       => Get_Reads,
1595          Get_Bodies      => Get_Bodies,
1596          Get_Declaration => False,
1597          Arr             => Arr.all,
1598          Index           => Index);
1599
1600       if Arr'Length /= 0 then
1601          Sort (Arr.all);
1602       end if;
1603
1604       return Arr;
1605    end Get_References;
1606
1607    ----------
1608    -- Free --
1609    ----------
1610
1611    procedure Free (Arr : in out Reference_Array_Access) is
1612       procedure Internal is new Ada.Unchecked_Deallocation
1613         (Reference_Array, Reference_Array_Access);
1614    begin
1615       Internal (Arr);
1616    end Free;
1617
1618    ------------------
1619    -- Is_Parameter --
1620    ------------------
1621
1622    function Is_Parameter (Decl : Declaration_Reference) return Boolean is
1623    begin
1624       return Decl.Is_Parameter;
1625    end Is_Parameter;
1626
1627 end Xr_Tabls;