OSDN Git Service

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