OSDN Git Service

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