File: xref.adb

package info (click to toggle)
gnat 3.10p-3
  • links: PTS
  • area: main
  • in suites: hamm, slink
  • size: 49,492 kB
  • ctags: 33,976
  • sloc: ansic: 347,844; ada: 227,415; sh: 8,759; yacc: 7,861; asm: 5,252; makefile: 3,632; objc: 475; cpp: 400; sed: 261; pascal: 95
file content (1900 lines) | stat: -rw-r--r-- 62,547 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                                 X R E F                                  --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--                            $Revision: 1.107 $                            --
--                                                                          --
--          Copyright (C) 1992-1997, Free Software Foundation, Inc.         --
--                                                                          --
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 2,  or (at your option) any later ver- --
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
-- for  more details.  You should have  received  a copy of the GNU General --
-- Public License  distributed with GNAT;  see file COPYING.  If not, write --
-- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
-- MA 02111-1307, USA.                                                      --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
--                                                                          --
------------------------------------------------------------------------------

with Atree;  use Atree;
with Einfo;  use Einfo;
with Elists; use Elists;
with Lib;    use Lib;
with Namet;  use Namet;
with Nlists; use Nlists;
with Osint;  use Osint;
with Opt;    use Opt;
with Output; use Output;
with Sinfo;  use Sinfo;
with Sinput; use Sinput;
with Snames; use Snames;
with Sprint; use Sprint;
with Stand;  use Stand;
with Uname;  use Uname;
with Unchecked_Deallocation;
with Xref_Tab; use Xref_Tab;

package body Xref is

   ---------------------
   --  File suffixes  --
   ---------------------

   Spec_REQ_Suffix : constant String := ".r";
   Body_REQ_Suffix : constant String := ".br";
   Org_Spec_Suffix : constant String := ".org";

   --  ??? the whole idea of a file suffix is too target dependent, and
   --  ??? the knowledge of suffixes should remain in OSINT.

   ------------------
   --  Other data  --
   ------------------

   type Phase_Type is (Add_Entities_And_Refs, Unmark_Refs);

   Phase : Phase_Type;
   --  Used to signal the Traverse_Node procedure what we're doing.
   --
   --    Add_Entities_And_REfs : normal mode to build the Entity_Tables.
   --
   --    Unmark_Refs           : special mode for multipass removal of
   --                            unused nodes within the program tree.

   type Hash_Record is record
      Serial : Nat;
      --  Serial number for hash table entry. A value of zero means that
      --  the entry is currently unused. The serial number is used for
      --  indexing tables of associated information for nodes.

      Id : Int;
      --  If serial number field is non-zero, contains corresponding Id value

      Prev_Inc_Typ_Def : Boolean := False;
      --  Set to True if the node corresponding to the serial
      --  number is the full declaration of an entity having
      --  a previous type definition.
   end record;

   Internal_Node : Boolean;

   type Hash_Table_Type is array (Nat range <>) of Hash_Record;
   type Access_Hash_Table_Type is access Hash_Table_Type;
   Hash_Table : Access_Hash_Table_Type;
   --  The hash table itself, see Serial_Number function for details of use

   Hash_Table_Len : Nat;
   --  Range of Hash_Table is from 0 .. Hash_Table_Len - 1 so that dividing
   --  by Hash_Table_Len gives a remainder that is in Hash_Table'Range.

   Hash_Slot : Nat;
   --  Set by an unsuccessful call to Serial_Number (one which returns zero)
   --  to save the slot that should be used if Set_Serial_Number is called.

   Next_Serial_Number : Nat;
   --  Number of last visited node or list. Used during the marking phase to
   --  set proper node numbers in the hash table.

   type Entity_Association_Type is array (Node_Id range <>) of Entity_Acc;
   type Access_Entity_Association_Type is access Entity_Association_Type;
   Entity_Association : Access_Entity_Association_Type;
   --  Array to associate the entities in the program tree with their
   --  Corresponding data structures.

   type File_Record is record
      Create_REQ : Boolean := False;
      Etbl       : Entity_Table_Acc;
   end record;

   type File_Array_Type is array (Unit_Number_Type range <>) of File_Record;
   type File_Array_Acc is access File_Array_Type;

   Loaded_Files : File_Array_Acc;
   --  Array that associates the loaded files with the Entity_Tables.
   --  Create_REQ is used in Write_Spec_REQs to build the REQ for a withed
   --  spec.

   type Ref_Array_Type is array (Int range <>) of Node_Id;
   type Ref_Array_Acc is access Ref_Array_Type;

   Ref_Buffer : Ref_Array_Acc;
   Ref_Length : Int;
   --  Array to buffer the found references until all entities are added
   --  to our entity lists.

   -------------------------
   --  Local subprograms  --
   -------------------------

   procedure Allocate_Memory;
   --  Allocates the memory on the heap which is needed for the dynamic
   --  arrays.

   procedure Collect_Withs (Unum : Unit_Number_Type);
   --  Collect with clauses in the context clause of the given compilation
   --  unit.

   procedure Deallocate_Memory;
   --  Frees the memory on the heap which is needed for the dynamic arrays.

   procedure Init_Numbers;
   --  Clear Node_Numbers and List_Numbers to False (= unmarked).
   --  Use Init_Numbers before each call of Traverse_Node_Hierarchic.

   procedure Link_Subunits (The_Unit : Unit_Number_Type);
   --  Links the main Entity_Table with its loaded subunits.

   procedure Remove_Entities
     (The_Etbl : Entity_Table_Acc;
      Found    : in out Boolean);
   --  Looks for entities with no references and removes both the fitting node
   --  and all its parents which also get redundant. This is done by a loop
   --  to provide succesive dead code removal.
   --  ??? need to document the function of the parameters, and Found in
   --  particular, what is it and why is it in out ???

   function Serial_Number (Id : Int) return Nat;
   --  Given a Node_Id, List_Id or Elist_Id, returns the previously assigned
   --  serial number, or zero if no serial number has yet been assigned.

   procedure Set_Serial_Number;
   --  Can be called only immediately following a call to Serial_Number that
   --  returned a value of zero. Causes the value of Next_Serial_Number to be
   --  placed in the hash table (corresponding to the Id argument used in the
   --  Serial_Number call), and increments Next_Serial_Number.

   procedure Set_Spec_REQ_Flags (The_Etbl : Entity_Table_Acc);
   --  Sets the Create_REQ fields to create a required interface for all
   --  withed specs as well as to select the transitive specs.

   procedure Traverse_Node_Hierarchic (N : Node_Id);
   --  Recursive procedure traversing the program tree.
   --  Can be used to add information to the Entity_Tables as well as
   --  to remove references of a dead program part (for dead code elimination).
   --  Before each call of Traverse_Node_Hierarchic the procedure
   --  Init_Numbers must be called to initialize the node and list flags.
   --  If an entity declaration is found, then the corresponding entity
   --  information gets immediately added to the fitting Entity_Table.
   --  Every reference which is found is buffered in Ref_Buffer to avoid
   --  the case of adding a reference pointing to an entity that doesn't yet
   --  appear in the fitting Entity_Table.

   procedure Write_Org (The_Etbl : Entity_Table_Acc);
   --  Writes the original source of the given Entity_Table (GNAT -dw conform).
   --  Used to compare the required interfaces with it and then to create the
   --  correct provided interface. File suffix changes to Org_Spec_Suffix.

   procedure Write_Body_REQs;
   --  Writes the REQs for the body and its subunits the disk.
   --  The file name of a Body_REQ is the file name of the compilation unit,
   --  the suffix '.adb' replaced by Body_REQ_Suffix.

   procedure Write_Spec_REQs;
   --  Writes the REQs (one for each withed spec) to the disk.
   --  The file name of a Spec_REQ is the file name of the withed
   --  compilation unit, the suffix '.ads' replaced by
   --  '.' & the name of the withing unit & Body_REQ_Suffix.
   --  e.g.   with Pack1;
   --         procedure Main is ...
   --  then we have the source file name main.adb and would get pack1.main.r
   --  with the Spec_REQ for Pack1 inside.

   procedure Write_Xref (The_Etbl : Entity_Table_Acc);
   --  Creates a cross reference list, containing all the entities and their
   --  corresponding references, which are found in the loaded files. The
   --  references are printed by file name and line numbers of their source
   --  locations. This call has no effect if the appropriate xref switchs
   --  are not set. What is the parameter ???

   -------------------
   -- Serial_Number --
   -------------------

   function Serial_Number (Id : Int) return Nat is
      H : Int := Id mod Hash_Table_Len;

   begin

      if Hash_Table (H).Id = Id and then Hash_Table (H).Prev_Inc_Typ_Def then
         Internal_Node := True;
         Hash_Slot := H;
         return Hash_Table (H).Serial;
      end if;

      while Hash_Table (H).Serial /= 0 loop

         if Id = Hash_Table (H).Id then
            return Hash_Table (H).Serial;
         end if;

         H := H + 1;

         if H > Hash_Table'Last then
            H := 0;
         end if;
      end loop;

      --  Entry was not found, save slot number for possible subsequent call
      --  to Set_Serial_Number, and unconditionally save the Id in this slot
      --  in case of such a call (the Id field is never read if the serial
      --  number of the slot is zero, so this is harmless in the case where
      --  Set_Serial_Number is not subsequently called).

      Hash_Slot := H;
      Hash_Table (H).Id := Id;
      return 0;

   end Serial_Number;

   -----------------------
   -- Set_Serial_Number --
   -----------------------

   procedure Set_Serial_Number is
   begin
      Hash_Table (Hash_Slot).Serial := Next_Serial_Number;
      Next_Serial_Number := Next_Serial_Number + 1;
   end Set_Serial_Number;

   ---------------------
   -- Allocate_Memory --
   ---------------------

   procedure Allocate_Memory is
   begin

      --  Pointers for direct entity access.

      Entity_Association := new Entity_Association_Type
        (Last_Standard_Node_Id + 1 .. Last_Node_Id);
      --  ??? THIS WON'T DO, YOU ARE ASSUMING Node_Id values are contiguous

      --  Array to associate the loaded files with their corresponding
      --  Entity_Table.

      Loaded_Files := new File_Array_Type (Main_Unit .. Last_Unit);

      --  Buffer for found references.

      Ref_Buffer := new Ref_Array_Type (1 ..
        Int (Last_Node_Id - Last_Standard_Node_Id));

      Ref_Length := 0;

      Hash_Table_Len := (150 * (Num_Nodes + Num_Lists + Num_Elists)) / 100;
      Hash_Table := new Hash_Table_Type  (0 .. Hash_Table_Len - 1);

   end Allocate_Memory;

   -------------------
   -- Collect_Withs --
   -------------------

   procedure Collect_Withs (Unum : Unit_Number_Type) is
      Item        : Node_Id;
      Withed_Unit : Unit_Number_Type;

   begin
      Item := First (Context_Items (Cunit (Unum)));
      while Present (Item) loop


         if Nkind (Item) = N_With_Clause
           and then not Implicit_With (Item)
         then
            Withed_Unit := Get_Cunit_Unit_Number (Library_Unit (Item));

            Add_With
              (Loaded_Files (Unum).Etbl, Loaded_Files (Withed_Unit).Etbl);
         elsif Nkind (Item) = N_With_Clause
           and then Implicit_With (Item)
         then
            Withed_Unit := Get_Cunit_Unit_Number (Library_Unit (Item));
            if Chars (Name (Item)) in Text_IO_Package_Name then
               Add_With
                 (Loaded_Files (Unum).Etbl, Loaded_Files (Withed_Unit).Etbl,
                  True);
               null;
            end if;
         end if;

         Item := Next (Item);
      end loop;
   end Collect_Withs;

   -----------------------
   -- Deallocate_Memory --
   -----------------------

   procedure Deallocate_Memory is

      procedure Free is new Unchecked_Deallocation (Entity_Association_Type,
        Access_Entity_Association_Type);

      procedure Free is new Unchecked_Deallocation (File_Array_Type,
        File_Array_Acc);

      procedure Free is new Unchecked_Deallocation (Ref_Array_Type,
        Ref_Array_Acc);

      procedure Free is new Unchecked_Deallocation (Hash_Table_Type,
        Access_Hash_Table_Type);

   begin
      Free (Entity_Association);
      Free (Loaded_Files);
      Free (Ref_Buffer);
      Free (Hash_Table);
   end Deallocate_Memory;

   --------------
   -- Finalize --
   --------------

   procedure Finalize is
   begin
      if Operating_Mode = Check_Syntax then
         return;
      end if;

      --  If we already called Write_Xref from Gather_Xref_Info for each file
      --  in the case where we want only smart information in the xref file
      --  (switches x3 and x4 of gnatf), then nothing to do

      if Xref_Flag and then not Global_Xref_File then
         return;

      --  Otherwise write the xref information now

      else
         Write_Xref (Xref_Tab.First_Etbl);
      end if;

   end Finalize;

   ----------------------
   -- Gather_Xref_Info --
   ----------------------

   procedure Gather_Xref_Info (Top : Node_Id) is
      Spec          : Unit_Number_Type;
      Unum          : Unit_Number_Type;
      To_Unum       : Unit_Number_Type;
      To_Entity     : Entity_Id;
      The_Entity    : Entity_Acc;
      Ref_Node      : Node_Id;
      Main_Etbl     : Entity_Table_Acc;
      Etbl_Tmp      : Entity_Table_Acc;
      Etbl_List     : Entity_Table_Acc;
      Renamed_Node  : Node_Id;
      Renamed_Sloc  : Source_Ptr;
      Renamed_Unit  : Unit_Number_Type;
      Renamed_Found : Boolean;
      Unit_Node     : Node_Id;

   begin
      --  Immediate return if not collecting Xref information
      --  (should this be a check of Xref_Analyze?)

      if Operating_Mode = Check_Syntax
        or else
          not (With_Warnings    or
               Xref_Flag        or
               Spec_REQs_Flag   or
               Body_REQs_Flag)
      then
         return;
      end if;

      --  Allocate dynamic arrays

      Allocate_Memory;

      --  Associate the loaded files with the Entity_Tables.
      --  Ignore Zombies (e.g. the spec for a body acting as spec)!

      Etbl_Tmp := Xref_Tab.Last_Etbl;
      for J in Loaded_Files'Range loop
         Add_Etbl (First_Etbl, Last_Etbl, J, Loaded_Files (J).Etbl);
      end loop;

      Main_Etbl  := Loaded_Files (Main_Unit).Etbl;

      --  We perform research research only for the entity tables
      --  that have been created in the current compilation.

      if Etbl_Tmp = null then
         Etbl_Tmp := Main_Etbl;
      else
         Etbl_Tmp := Etbl_Tmp.Next_Etbl;
      end if;

      while Etbl_Tmp /= null loop

         if Nkind (Unit (Etbl_Tmp.Top_Node)) =
                             N_Package_Renaming_Declaration
         then
            Renamed_Node := Name (Unit (Etbl_Tmp.Top_Node));
            Renamed_Found := False;

            --  Searches the node of the renamed package and the name of
            --  the corresponding file where this package is declared.

            while not Renamed_Found loop
               Renamed_Node := Parent (Node_Id (Entity (Renamed_Node)));

               if Nkind (Renamed_Node) =
                  N_Package_Renaming_Declaration
               then
                  Renamed_Node := Name (Renamed_Node);
               else
                  Renamed_Found := True;
               end if;
            end loop;

            Renamed_Sloc := Sloc (Renamed_Node);
            Renamed_Unit := Get_Sloc_Unit_Number (Renamed_Sloc);
            Get_Name_String (Full_File_Name (Source_Index (Renamed_Unit)));

            --  Searches the corresponding Etbl

            Etbl_List := First_Etbl;
            while Etbl_List /= null loop
               if Etbl_List.File_Name.all = Name_Buffer (1 .. Name_Len) then
                  Etbl_Tmp.Renamed_Etbl := Etbl_List;
                  exit;
               end if;

               Etbl_List := Etbl_List.Next_Etbl;
            end loop;
         end if;

         Etbl_Tmp := Etbl_Tmp.Next_Etbl;
      end loop;

      --  We mark the main Entity_Table as a 'required unit', that is
      --  we create a fully detailed Xref for it.

      Main_Etbl.RU := True;

      --  Look for with clauses within the loaded files.

      --  Ignore Zombies (e.g. the spec for a body acting as spec) and
      --  do this only once ('Examined' signals a previous examination)!

      for J in Loaded_Files'Range loop
         if not Loaded_Files (J).Etbl.Examined then
            Collect_Withs (J);
         end if;
      end loop;

      --  Here we link the multiple parts of an object
      --  (i.e. Spec/Body/Subunits) to give correct With_Warnings.

      case Main_Etbl.Status is

         when A_Body =>

            Spec := Get_Cunit_Unit_Number (Library_Unit (Top));

            if Spec_REQs_Flag then
               Write_Org (Loaded_Files (Spec).Etbl);
            end if;

            Loaded_Files (Spec).Etbl.RU := True;
            Loaded_Files (Spec).Create_REQ := True;

            --  In multifile mode we create full output for this spec.
            --  Otherwise we print only what is used.

            Loaded_Files (Spec).Etbl.Status := Withed_Spec;

            Loaded_Files (Spec).Etbl.Successor := Main_Etbl;

            Main_Etbl.Predecessor := Loaded_Files (Spec).Etbl;
            Link_Subunits (Main_Unit);

         when Sub_Body =>

            Unum := Get_Cunit_Unit_Number (Library_Unit (Top));
            Loaded_Files (Unum).Etbl.RU := True;

            if Loaded_Files (Unum).Etbl.Status = A_Body then
               Spec := Get_Cunit_Unit_Number (Library_Unit (Cunit (Unum)));

               if Spec_REQs_Flag then
                  Write_Org (Loaded_Files (Spec).Etbl);
               end if;

               --  In multifile mode we create full output for this spec.
               --  Otherwise we print only what is used.
               Loaded_Files (Spec).Etbl.RU := True;

               Loaded_Files (Spec).Etbl.Status := Withed_Spec;

               Loaded_Files (Spec).Etbl.Successor :=
                 Loaded_Files (Unum).Etbl;

               Loaded_Files (Unum).Etbl.Predecessor :=
                 Loaded_Files (Spec).Etbl;
            end if;

            Link_Subunits (Unum);

         when Body_As_Spec =>

            Link_Subunits (Main_Unit);

         when A_Spec | Withed_Spec =>

            if Spec_REQs_Flag then
               Write_Org (Main_Etbl);
            end if;

      end case;

      --  After linking the main unit with its predecessors and successors
      --  some other units must also be examined
      --     - bodies of generic packages must be linked
      --     - Child spec must be linked with their parents

      for All_The_Units in Loaded_Files'Range loop

         --  if this entity table has not been linked yet then
         --  we must examine it

         if not Loaded_Files (All_The_Units).Etbl.Linked then
            case Loaded_Files (All_The_Units).Etbl.Status is
               when A_Spec | Withed_Spec =>
                  Unit_Node :=
                    Unit (Loaded_Files (All_The_Units).Etbl.Top_Node);
                  if Parent_Spec (Unit_Node) /= Empty then

                     --  If parent_spec is not empty then the current spec
                     --  is a child spec. So we get the parent spec and set up
                     --  the predecessor and successor links

                     Spec := Get_Cunit_Unit_Number (Parent_Spec (Unit_Node));

                     --  Adds Child_Spec to the list of children of the parent

                     Etbl_Tmp := Loaded_Files (Spec).Etbl;

                     if Etbl_Tmp.First_Child = null then
                        Etbl_Tmp.First_Child := new Child_Spec;
                        Etbl_Tmp.First_Child.Child_Etbl :=
                          Loaded_Files (All_The_Units).Etbl;
                     else
                        declare
                           Child_Units : Child_Spec_Acc :=
                                            Etbl_Tmp.First_Child;
                        begin
                           while Child_Units.Next_Child /= null loop
                              Child_Units := Child_Units.Next_Child;
                           end loop;

                           Child_Units.Next_Child := new Child_Spec;
                           Child_Units.Next_Child.Child_Etbl :=
                             Loaded_Files (All_The_Units).Etbl;
                        end;
                     end if;

                     Loaded_Files (All_The_Units).Etbl.Predecessor :=
                       Etbl_Tmp;

                  end if;

               when A_Body =>

                  --  We get the corresponding spec

                  Spec := Get_Cunit_Unit_Number
                            (Library_Unit (Cunit (All_The_Units)));

                  --  We set up the predecessor and successor links

                  Loaded_Files (All_The_Units).Etbl.Predecessor :=
                    Loaded_Files (Spec).Etbl;

                  Loaded_Files (Spec).Etbl.Successor :=
                    Loaded_Files (All_The_Units).Etbl;

               when Sub_Body =>
                  Unum := Get_Cunit_Unit_Number (Library_Unit
                                                   (Cunit (All_The_Units)));
                  Etbl_Tmp := Loaded_Files (Unum).Etbl;

                  Loaded_Files (All_The_Units).Etbl.Predecessor := Etbl_Tmp;

                  while Etbl_Tmp.Successor /= null loop
                     Etbl_Tmp := Etbl_Tmp.Successor;
                  end loop;

                  Etbl_Tmp.Successor := Loaded_Files (All_The_Units).Etbl;

               when others =>
                  null;

            end case;

         end if;

         Loaded_Files (All_The_Units).Etbl.Linked := True;

      end loop;

      Set_Spec_REQ_Flags (Main_Etbl);

      --  Search and add the entities to the entity tables.

      Phase := Add_Entities_And_Refs;

      --  Hierarchic scan of the nodes instead of a linear scan
      --  It must be checked that the hierarchic scan is not
      --  too much slower than the linear onw

      for All_The_Units in Main_Unit .. Last_Unit loop
         Init_Numbers;
         Traverse_Node_Hierarchic (Cunit (All_The_Units));
      end loop;

      --  Take the references from the buffer and add them to the
      --  fitting entities.

      for J in 1 .. Ref_Length loop
         Ref_Node := Ref_Buffer (J);

         --  if the reference node is matches a with clause. Then we skip
         --  this reference if the with clause is implicit.
         --  It's mainly the case when a child unit is withed. Implicit withs
         --  are generated for all the parent specs.

         if not (Nkind (Parent (Ref_Node)) = N_With_Clause
                   and then Implicit_With (Parent (Ref_Node)))
         then

            To_Entity := Entity (Ref_Node);

            Unum    := Get_Sloc_Unit_Number (Sloc (Ref_Node));
            To_Unum := Get_Sloc_Unit_Number (Sloc (Entity (Ref_Node)));

            --  We don't add reference :
            --     - for entities declared in Specs that are referenced in a
            --       successor of this spec
            --     - for entities declared in bodies

            To_Entity := Entity (Ref_Node);

            if not All_Info_In_Xref
              and then
                (Nkind (Parent (To_Entity)) = N_Enumeration_Type_Definition
                  or else
                    Nkind (Parent (To_Entity)) = N_Component_Declaration)
            then
               loop
                  To_Entity := Parent (To_Entity);
                  exit when Nkind (To_Entity) = N_Full_Type_Declaration
                    or else Nkind (To_Entity) = N_Protected_Type_Declaration;
               end loop;

               To_Entity := Defining_Identifier (To_Entity);
            end if;

            The_Entity := Entity_Association (To_Entity);

            if Unum = To_Unum
              and then Loaded_Files (Unum).Etbl.Status in Body_Status
              and then not All_Info_In_Xref
              and then not Include_Inlined

            then
               --  We update The_Entity.Length to avoid junk messages.

               if Nkind (Parent (Ref_Node)) /= N_Pragma_Argument_Association
                 and then The_Entity /= null
               then
                  The_Entity.Length := The_Entity.Length + 1;
               end if;

            else
               if not Loaded_Files (Unum).Etbl.Examined then

                  Add_Reference
                    (The_Entity, Loaded_Files (Unum).Etbl, Ref_Node);

                  if Nkind (Parent (Ref_Node)) in N_Generic_Instantiation then

                     declare
                        Ref_Etbl : constant Entity_Table_Acc :=
                                     Loaded_Files (Unum).Etbl;
                        Ent_Etbl : constant Entity_Table_Acc :=
                                     Loaded_Files (To_Unum).Etbl;
                        I_Tmp    : Include_Acc;

                     begin
                        I_Tmp := Ref_Etbl.First_Include;

                        if I_Tmp = null then
                           Ref_Etbl.First_Include := new Include;
                           Ref_Etbl.First_Include.Included_Etbl := Ent_Etbl;

                        else
                           while I_Tmp.Included_Etbl /= Ent_Etbl
                             and then I_Tmp.Next_Include /= null
                           loop
                              I_Tmp := I_Tmp.Next_Include;
                           end loop;

                           if I_Tmp.Included_Etbl /= Ent_Etbl then
                              I_Tmp.Next_Include := new Include;
                              I_Tmp.Next_Include.Included_Etbl := Ent_Etbl;
                           end if;
                        end if;
                     end;
                  end if;

               elsif Spec_REQs_Flag
                 and then Loaded_Files (Unum).Create_REQ
                 and then Unum = To_Unum
               then
                  Update_Reference
                    (The_Entity, Loaded_Files (Unum).Etbl, Ref_Node);
               end if;
            end if;
         end if;
      end loop;


      --  Write the Spec_REQs.

      if Spec_REQs_Flag then
         Write_Spec_REQs;
      end if;

      --  Write the Body_REQs.

      if Body_REQs_Flag
        and then Loaded_Files (Main_Unit).Etbl.Status in Body_Status
      then
         Write_Body_REQs;
      end if;

      --  Mark the units to be Examined.

      for J in Loaded_Files'Range loop
         if Loaded_Files (J).Etbl /= null then
            Loaded_Files (J).Etbl.Examined := True;
         end if;
      end loop;

      if Xref_Flag and then not Global_Xref_File then
         Write_Xref (Main_Etbl);
      end if;

      --  Deallocate dynamic arrays

      Deallocate_Memory;

   end Gather_Xref_Info;

   ------------------
   -- Init_Numbers --
   ------------------

   procedure Init_Numbers is
   begin
      --  Set node flags to unvisited (except those of Standard).

      --  Allocate and clear serial number hash table. The size is 150% of
      --  the maximum possible number of entries, so that the hash table
      --  cannot get significantly overloaded.

      for J in Hash_Table'Range loop
         Hash_Table (J).Serial := 0;
      end loop;

      Next_Serial_Number := 1;

   end Init_Numbers;

   ----------------
   -- Initialize --
   ----------------

   procedure Initialize is
   begin

      With_Warnings       := Xref_Flag_1 or Xref_Flag_2;

      Entity_Warnings     := Xref_Flag_2;

      Xref_Flag           := Xref_Flag_3 or Xref_Flag_4 or Xref_Flag_5
                               or Xref_Flag_6;

      Entity_Info_In_Xref := Xref_Flag_6;

      All_Info_In_Xref    := Xref_Flag_5 or Xref_Flag_6;

      Global_Xref_File    := Xref_Flag_6;

      Include_Inlined     := Xref_Flag_4;

      Spec_REQs_Flag      := Xref_Flag_S;

      Body_REQs_Flag      := Xref_Flag_B;

      Xref_Analyze        := (With_Warnings
                                or else Spec_REQs_Flag
                                or else Body_REQs_Flag
                                or else Xref_Flag)
                             and then Operating_Mode /= Check_Semantics;

      --  Above test of Operating_Mode is incomprehensible!


   end Initialize;

   -------------------
   -- Link_Subunits --
   -------------------

   procedure Link_Subunits (The_Unit : Unit_Number_Type) is
      Top_Node  : constant Node_Id := Cunit (The_Unit);
      Etbl_Tmp  : Entity_Table_Acc;

   begin
      Etbl_Tmp := Loaded_Files (The_Unit).Etbl;

      for J in Loaded_Files'Range loop
         if Loaded_Files (J).Etbl /= null
           and then Loaded_Files (J).Etbl.Kind = Subunit
           and then J /= The_Unit
           and then Library_Unit (Cunit (J)) = Top_Node
           and then Loaded_Files (J).Etbl.Predecessor = null
         then
            while Etbl_Tmp.Successor /= null loop
               Etbl_Tmp := Etbl_Tmp.Successor;
            end loop;

            Etbl_Tmp.Successor := Loaded_Files (J).Etbl;

            --  Temporary The predecessor of a subunit is the body
            --  where the stub is defined  ???

            Loaded_Files (J).Etbl.Predecessor := Loaded_Files (The_Unit).Etbl;
            Loaded_Files (J).Etbl.Linked := True;
         end if;
      end loop;

      Loaded_Files (The_Unit).Etbl.Linked := True;
   end Link_Subunits;

   ---------------------
   -- Remove_Entities --
   ---------------------

   procedure Remove_Entities
     (The_Etbl : Entity_Table_Acc;
      Found    : in out Boolean)
   is
      E_Tmp : Entity_Acc;
      --  To store the current entity within the loop.

      procedure Remove_Element (The_Node : Node_Id);
      --  Removes the given node and also the surrounding Ada construct.

      procedure Remove_Pragmas (The_Entity : Entity_Acc);
      --  Removes all the pragma nodes within the program tree which
      --  apply on the given entity.

      --------------------
      -- Remove_Element --
      --------------------

      procedure Remove_Element (The_Node : Node_Id) is
         L_Tmp : List_Id;
         P_Tmp : Node_Id;

         procedure Remove_List;

         procedure Remove_List is
            L_Tmp : List_Id;
            P_Tmp : Node_Id;

         begin
            P_Tmp := Parent (The_Node);

            if Is_List_Member (The_Node) then
               L_Tmp := List_Containing (The_Node);

               --  Cancel the references in the subtree of The_Node;

               Traverse_Node_Hierarchic (The_Node);
               Remove (The_Node);

               if Is_Empty_List (L_Tmp) then
                  Remove_Element (P_Tmp);
               end if;

            else
               --  Cancel the references in the subtree of The_Node

               Traverse_Node_Hierarchic (The_Node);
               Remove_Element (P_Tmp);
            end if;
         end Remove_List;

      begin
         if Nkind (The_Node) in N_Entity then

         --  If we get a N_Defining_Identifier, N_Defining_Character_Literal or
         --  N_Defining_Operator_Symbol, then we have to distinguish between
         --  the various kinds of entities.

            case Ekind (The_Node) is

               --  We don't remove void entities since they are used internally

               when E_Void =>
                  null;

               --  Don't do anything with components, since it is very tricky
               --  to find a hidden reference for a record component (e.g. in
               --  an aggregate, all components are implicitly referenced).

               when E_Component =>
                  null;

               --  Main processing for most cases

               when E_Access_Protected_Subprogram_Type  |
                    E_Access_Subtype                    |
                    E_Access_Type                       |
                    E_Array_Subtype                     |
                    E_Array_Type                        |
                    E_Block                             |
                    E_Class_Wide_Subtype                |
                    E_Class_Wide_Type                   |
                    E_Constant                          |
                    E_Decimal_Fixed_Point_Type          |
                    E_Decimal_Fixed_Point_Subtype       |
                    E_Discriminant                      |
                    E_Entry                             |
                    E_Entry_Family                      |
                    E_Entry_Index_Parameter             |
                    E_Enum_Table_Type                   |
                    E_Enumeration_Subtype               |
                    E_Enumeration_Type                  |
                    E_Exception                         |
                    E_Exception_Type                    |
                    E_Floating_Point_Subtype            |
                    E_Floating_Point_Type               |
                    E_General_Access_Type               |
                    E_Incomplete_Type                   |
                    E_Label                             |
                    E_Loop                              |
                    E_Loop_Parameter                    |
                    E_Modular_Integer_Subtype           |
                    E_Modular_Integer_Type              |
                    E_Named_Integer                     |
                    E_Named_Real                        |
                    E_Ordinary_Fixed_Point_Type         |
                    E_Ordinary_Fixed_Point_Subtype      |
                    E_Protected_Object                  |
                    E_Protected_Subtype                 |
                    E_Protected_Type                    |
                    E_Record_Subtype                    |
                    E_Record_Type                       |
                    E_Signed_Integer_Subtype            |
                    E_Signed_Integer_Type               |
                    E_String_Literal_Subtype            |
                    E_String_Subtype                    |
                    E_String_Type                       |
                    E_Subprogram_Type                   |
                    E_Task_Subtype                      |
                    E_Task_Type                         |
                    E_Variable                          =>

                  Remove_List;

               --  Private type processing

               when E_Limited_Private_Subtype           |
                    E_Limited_Private_Type              |
                    E_Private_Subtype                   |
                    E_Private_Type                      |
                    E_Record_Subtype_With_Private       |
                    E_Record_Type_With_Private          =>

                  Remove_Element (Full_View (The_Node));
                  Remove_List;

               --  Since it's very tricky to find a hidden reference for an
               --  enumeration literal we do nothing (e.g. in a loop from
               --  type'First to type'Last all literals are automatically
               --  referenced).

               when E_Enumeration_Literal =>
                  null;

               --  Compilation unit nodes are not removed since
               --  this causes a lot of trouble.

               when E_Function                          |
                    E_Operator                          |
                    E_Package                           |
                    E_Procedure                         =>

                  if Scope (The_Node) > Last_Standard_Node_Id then

                     --  Cancel the references in the subtree of The_Node.

                     Traverse_Node_Hierarchic (The_Node);

                     P_Tmp := Parent (The_Node);
                     Remove_Element (P_Tmp);

                     --  There are only two possibilities in this case:
                     --  Either the parent is a N_Function_Specification or
                     --  a N_Procedure_Specification.

                  end if;

               --  Cannot delete a parameter of a subprogram (or at least not
               --  easily because it would have all sorts of consequences)

               when E_In_Out_Parameter                  |
                    E_In_Parameter                      |
                    E_Out_Parameter                     =>

                  null;

               --  For the moment, forget the case of generics and their formal
               --  parameters. Might try to do something later here ???

               when E_Generic_Function                  |
                    E_Generic_In_Out_Parameter          |
                    E_Generic_In_Parameter              |
                    E_Generic_Package                   |
                    E_Generic_Procedure                 =>

                  null;

               --  Body entities have no significance semantically, so ignore

               when E_Package_Body                      |
                    E_Protected_Body                    |
                    E_Subprogram_Body                   |
                    E_Task_Body                         =>

                  null;

               --  Internal allocator and access types should never appear
               --  at the stage a cross-reference is being computed

               when E_Access_Subprogram_Type            |
                    E_Access_Attribute_Type             |
                    E_Allocator_Type                    |
                    E_Anonymous_Access_Type             =>

                  pragma Assert (False);
                  raise Program_Error;
            end case;

         else
            case Nkind (The_Node) is

               when N_Empty =>
                  null;

               when N_Function_Specification .. N_Procedure_Specification =>

                  --  There are only two possibilities in this case:
                  --  Either the parent is a N_Subprogram_Declaration or
                  --  a N_Subprogram_Body.

                  P_Tmp := Parent (The_Node);
                  Remove_Element (P_Tmp);

               when N_Component_List | N_Record_Definition =>

                  --  These are intermediate nodes.
                  --  In this cases we don't remove the parent
                  --  (e.g. N_Record_Definition for a N_Component_List)
                  --  since the Record identifier is treated separately.

                  null;

               when N_Object_Declaration =>
                  if Is_List_Member (The_Node) then
                     L_Tmp := List_Containing (The_Node);
                     P_Tmp := Parent (The_Node);

                     Traverse_Node_Hierarchic (The_Node);
                     --  To cancel the references in the subtree of The_Node.

                     Remove (The_Node);

                     --  Here we do *not* remove the parent since then we
                     --  would delete the whole subprogram.
                  end if;

               when others =>
                  Remove_List;
            end case;
         end if;

      end Remove_Element;

      --------------------
      -- Remove_Pragmas --
      --------------------

      procedure Remove_Pragmas (The_Entity : Entity_Acc) is
         R_Tmp : Ref_Acc := Xref_Tab.First (The_Entity);

      begin
         while not Is_Null (R_Tmp) loop

            if Is_Pragma (R_Tmp) then
               Remove_Element (Parent (Parent (The_Node (R_Tmp))));
            end if;

            R_Tmp := Next (R_Tmp);
         end loop;

      end Remove_Pragmas;

   -------------------------------------------
   --  Start Processing for Remove_Entities --
   -------------------------------------------

   begin
      E_Tmp := The_Etbl.First_Entity;
      Found := False;

      Phase := Unmark_Refs;
      Init_Numbers;

      while not Is_Null (E_Tmp) loop

         if Number_Of_Marks (E_Tmp) = 0
           and then Give_Warning (E_Tmp)
         then
            --  Update the Entity_Table:

            Found := True;

            --  We mark the entity in our entity table for the next pass
            --  to say: Don't remove this entity twice!

            Mark_Entity (E_Tmp);

            --  Update the program tree:
            --
            --  Since we need E_Tmp to find the pragmas, we have to
            --  remove the pragmas here rather than in Remove_Element

            if Entity_Type (E_Tmp) in E_Function .. E_Procedure then
               Remove_Pragmas (E_Tmp);
            end if;

            --  Remove the entities with no references.

            Remove_Element (Entity_Node (E_Tmp));

         end if;

         E_Tmp := Next (E_Tmp);

      end loop;
   end Remove_Entities;

   -------------------------
   -- Set_Spec_REQ_Flags  --
   -------------------------

   procedure Set_Spec_REQ_Flags (The_Etbl : Entity_Table_Acc) is
      Etbl_Tmp    : Entity_Table_Acc;
      With_Clause : With_Acc;

   begin
      --  Mark a spec withed by The_Etbl or a predecessor.

      Etbl_Tmp := The_Etbl;
      while Etbl_Tmp /= null loop

         With_Clause := Etbl_Tmp.First_With;
         while With_Clause /= null loop

            if With_Clause.Withed_Etbl.Kind /= Genr then
               Loaded_Files (Get_Cunit_Unit_Number
                 (With_Clause.Withed_Etbl.Top_Node)).Create_REQ := True;
            end if;

            --  Note: we don't create a REQ for a generic.

            With_Clause.Withed_Etbl.Status := Withed_Spec;
            With_Clause := With_Clause.Next_With;
         end loop;

         Etbl_Tmp := Etbl_Tmp.Predecessor;
      end loop;

      --  Mark a spec withed by a successor.

      Etbl_Tmp := The_Etbl.Successor;

      while Etbl_Tmp /= null loop

         With_Clause := Etbl_Tmp.First_With;
         while With_Clause /= null loop

            if With_Clause.Withed_Etbl.Kind /= Genr then
               Loaded_Files (Get_Cunit_Unit_Number
                 (With_Clause.Withed_Etbl.Top_Node)).Create_REQ := True;
            end if;

            --  Note: we don't create a REQ for a generic.

            With_Clause.Withed_Etbl.Status := Withed_Spec;
            With_Clause := With_Clause.Next_With;
         end loop;

         Etbl_Tmp := Etbl_Tmp.Successor;
      end loop;

   end Set_Spec_REQ_Flags;

   ------------------------------
   -- Traverse_Node_Hierarchic --
   ------------------------------

   procedure Traverse_Node_Hierarchic (N : Node_Id) is
      Kind        : Node_Kind;
      Unum        : Unit_Number_Type;
      To_Unum     : Unit_Number_Type;
      To_Entity   : Entity_Id;
      --  Only to reduce the length of some function calls.

      procedure Mark_Full_Declaration (N : Node_Id);
      --  Marks the node corresponding to the full declaration of N
      --  as having a previous incomplete definition

      procedure Visit_List (L : List_Id);
      --  Visits the nodes of a list in the program tree

      procedure Visit_Elist (E : Elist_Id);

      procedure Visit_Descendent (D : Union_Id);
      pragma Inline (Visit_Descendent);
      --  Visits a descendent of a node, where D is the descendent

      -------------------
      -- Mark_Internal --
      -------------------

      procedure Mark_Full_Declaration (N : Node_Id) is
         Parent_Node : constant Node_Id := Parent (N);
         H           : Nat;

      begin

         if Nkind (Parent_Node) = N_Private_Type_Declaration
           or else Nkind (Parent_Node) = N_Private_Extension_Declaration
           or else (Nkind (Parent_Node) = N_Object_Declaration
                    and then Constant_Present (Parent_Node)
                    and then Expression (Parent_Node) = Empty)
         then
            H := Int (Full_View (N)) mod Hash_Table_Len;
            Hash_Table (H).Id := Int (Full_View (N));
            Hash_Table (H).Prev_Inc_Typ_Def := True;
         end if;
      end Mark_Full_Declaration;

      -----------------
      -- Visit_Elist --
      -----------------

      procedure Visit_Elist (E : Elist_Id) is
         M : Elmt_Id;
         S : constant Nat := Serial_Number (Int (E));

      begin
         if S /= 0 then
            return;
         else
            Set_Serial_Number;
         end if;

         M := First_Elmt (E);

         while Present (M) loop
            Traverse_Node_Hierarchic (Node (M));
            M := Next_Elmt (M);
         end loop;
      end Visit_Elist;

      ----------------
      -- Visit_List --
      ----------------

      procedure Visit_List (L : List_Id) is
         N : Node_Id;
         S : constant Nat := Serial_Number (Int (L));

      begin

         if S /= 0 then
            return;
         else
            Set_Serial_Number;
         end if;

         N := First (L);

         if N /= Empty then
            while Next (N) /= Empty loop
               Traverse_Node_Hierarchic (N);
               N := Next (N);
            end loop;
         end if;

         Traverse_Node_Hierarchic (N);
      end Visit_List;

      ----------------------
      -- Visit_Descendent --
      ----------------------

      procedure Visit_Descendent (D : Union_Id) is
      begin
         if D in Node_Range then
            if D <= Union_Id (Empty_Or_Error) then
               return;
            end if;

            if Sloc (Node_Id (D)) <= Standard_Location then
               if Sloc (N) > Standard_Location then
                  return;
               end if;
            else
               if Sloc (N) <= Standard_Location
                 or else Sloc (N) = No_Location
                 or else Sloc (Node_Id (D)) = No_Location
                 or else Get_Sloc_Unit_Number (Sloc (Node_Id (D))) /=
                         Get_Sloc_Unit_Number (Sloc (N))
               then
                  return;
               end if;
            end if;

            if Parent (Node_Id (D)) /= Empty
              and then Parent (Node_Id (D)) /= N
            then
               return;
            end if;

            Traverse_Node_Hierarchic (Node_Id (D));

         elsif D in List_Range then
            if D = Union_Id (No_List)
              or else D = Union_Id (Error_List)
              or else Is_Empty_List (List_Id (D))
            then
               return;
            else
               Visit_List (List_Id (D));
            end if;

         elsif D in Elist_Range then
            if D = Union_Id (No_Elist)
              or else Is_Empty_Elmt_List (Elist_Id (D))
            then
               return;
            else
               Visit_Elist (Elist_Id (D));
            end if;

         else
            null;
         end if;
      end Visit_Descendent;

   ------------------------------------------------------
   -- Start of Processing for Traverse_Node_Hierarchic --
   ------------------------------------------------------

   begin
      if N = Empty then
         return;
      end if;

      Internal_Node := False;

      if Serial_Number (Int (N)) /= 0 then
         return; -- already visited
      else
         Set_Serial_Number;
      end if;

      Kind := Nkind (N);

      --  Look for named numbers or other constructs which get transformed
      --  into the corresponding litterals during semantics.

      if Kind = N_Package_Declaration and then
        Generic_Parent (Specification (N)) /= Empty
      then
         Traverse_Node_Hierarchic
           (Defining_Unit_Name (Specification (N)));
      end if;

      if Is_Rewrite_Substitution (N) then
         Traverse_Node_Hierarchic (Original_Node (N));
      end if;

      if Kind in N_Entity
        and then Ekind (N) /= E_Void
        and then Comes_From_Source (N)
        and then Parent (N) /= Empty
      then
         --  In the case we don't want the whole cross reference list to be
         --  generated we don't add declaration of :
         --     - enumeration litterals
         --     - record components
         --     - Parameters

         if (All_Info_In_Xref
              or else
                (Nkind (Parent (N)) /= N_Enumeration_Type_Definition
                  and then Nkind (Parent (N)) /= N_Component_Declaration))
           and then not Internal_Node
         then
            Unum := Get_Sloc_Unit_Number (Sloc (N));

            case Phase is

               when Add_Entities_And_Refs =>

                  if Loaded_Files (Unum).Etbl.Examined then
                     Update_Entity (Loaded_Files (Unum).Etbl,
                       N, Entity_Association (N));
                  else
                     Add_Entity (Loaded_Files (Unum).Etbl,
                       N, Entity_Association (N));
                  end if;

                  Mark_Full_Declaration (N);

               when Unmark_Refs =>

                  --  We mark the entity and all its descendents in our
                  --  entity table for the next pass to say:
                  --  Don't remove this entity twice! It's already removed.

               Mark_Entity (In_E_List (Loaded_Files (Unum).Etbl, N));

            end case;
         end if;

      elsif Kind = N_Identifier then

         --  In the case we don't want the whole cross-reference list to be
         --  generated we don.t add reference to parameters.

         if Nkind (Parent (N)) = N_Range
           and then Parent (Parent (N)) = Empty
         then
            --  We don't accept things like an internal range declaration

            null;

         elsif Entity (N) > Last_Standard_Node_Id then

         --  We suppress references to standard entities (e.g. integer)

            case Phase is
               when Add_Entities_And_Refs =>

                  --  Check that we don't add an internal reference

                  if Sloc (N) > 0 then
                     Ref_Length := Ref_Length + 1;
                     Ref_Buffer (Ref_Length) := N;
                  end if;

               when Unmark_Refs          =>
                  To_Entity := Entity (N);
                  To_Unum := Get_Sloc_Unit_Number (Sloc (To_Entity));
                  Unmark_Reference (Entity_Association (To_Entity), N);
            end case;
         end if;

      elsif (Kind in N_Op
              or else Kind = N_Attribute_Reference
              or else Kind = N_Character_Literal
              or else Kind = N_Expanded_Name
              or else Kind = N_Operator_Symbol)
        and then Entity (N) > Last_Standard_Node_Id
      then
         case Phase is
            when Add_Entities_And_Refs =>

               --  Checks that we don't add an internal reference

               if Sloc (N) > 0 then
                  Ref_Length := Ref_Length + 1;
                  Ref_Buffer (Ref_Length) := N;
               end if;

            when Unmark_Refs =>
               To_Entity := Entity (N);
               To_Unum := Get_Sloc_Unit_Number (Sloc (To_Entity));
               Unmark_Reference (Entity_Association (To_Entity), N);
         end case;
      end if;

      declare
         use Unchecked_Access;

      begin
         Visit_Descendent (Field1 (N));
         Visit_Descendent (Field2 (N));
         Visit_Descendent (Field3 (N));
         Visit_Descendent (Field4 (N));
         Visit_Descendent (Field5 (N));

         if Atree.Has_Extension (N) then
            Visit_Descendent (Field6 (N));
            Visit_Descendent (Field7 (N));
            Visit_Descendent (Field8 (N));
            Visit_Descendent (Field9 (N));
            Visit_Descendent (Field10 (N));
            Visit_Descendent (Field11 (N));
            Visit_Descendent (Field12 (N));
            Visit_Descendent (Field13 (N));
            Visit_Descendent (Field14 (N));
         end if;
      end;
   end Traverse_Node_Hierarchic;

   ---------------
   -- Write_Org --
   ---------------

   procedure Write_Org (The_Etbl : Entity_Table_Acc) is
   begin
      Name_Len := The_Etbl.File_Name'Length;
      Name_Buffer (1 .. Name_Len) := The_Etbl.File_Name.all;
      Name_Buffer (Name_Len - 3 ..
                   Name_Len - 4 + Org_Spec_Suffix'Length) := Org_Spec_Suffix;
      Name_Buffer (Name_Len - 3 + Org_Spec_Suffix'Length) := Ascii.NUL;

      Create_Req_Output;

      Sprint_Node (The_Etbl.Top_Node);

      Write_Eol;
      Set_Standard_Output;
      Close_Xref_Output;
   end Write_Org;

   ---------------------
   -- Write_Body_REQs --
   ---------------------

   procedure Write_Body_REQs is
      Main_Etbl  : Entity_Table_Acc := Loaded_Files (Main_Unit).Etbl;
      Etbl_Tmp_1 : Entity_Table_Acc;
      Etbl_Tmp_2 : Entity_Table_Acc;

      First : Boolean;
      Found : Boolean;

      procedure Open_File (The_Etbl : Entity_Table_Acc);
      --  Open file to write Body_REQs

      procedure Close_File;
      --  Close the file after Body_REQs are written

      procedure Open_File (The_Etbl : Entity_Table_Acc) is
      begin
         --  Here we build the file name of the Body_REQ.
         --  The file name is the file name of the body,
         --  the suffix '.adb' changed into Body_REQ_Suffix !

         Name_Len := The_Etbl.File_Name.all'Length;
         Name_Buffer (1 .. Name_Len) := The_Etbl.File_Name.all;
         Name_Buffer (Name_Len - 3 .. Name_Len - 4 + Body_REQ_Suffix'Length)
           := Body_REQ_Suffix;
         Name_Buffer (Name_Len - 3 + Body_REQ_Suffix'Length) := Ascii.NUL;

         Create_Req_Output;
      end Open_File;

      procedure Close_File is
      begin
         Write_Eol;
         Set_Standard_Output;
         Close_Xref_Output;
      end Close_File;

   --  Start of processing for Write_Body_REQs

   begin
      Etbl_Tmp_1 := Main_Etbl;
      Etbl_Tmp_2 := Main_Etbl;
      First      := True;

      while Etbl_Tmp_1 /= null loop

         --  First we have to mark the body and its subunits across each
         --  others.

         while Etbl_Tmp_2 /= null loop

            Clear_And_Mark_Xrefs (Etbl_Tmp_1, Etbl_Tmp_2, First, False);
            First := False;

            Etbl_Tmp_2 := Etbl_Tmp_2.Successor;
         end loop;

         --  Then remove the entities with no references step by step until
         --  all the remaining entities have one or more references. This must
         --  be done within a loop because after having removed some entities
         --  an earlier defined entity may become removable.

         --  Write_Org (Etbl_Tmp_1);  can be inserted to measure dead code ???

         Found := True;
         while Found loop
            Remove_Entities (Etbl_Tmp_1, Found);
         end loop;

         Open_File (Etbl_Tmp_1);

         --  CC
         --  don't touch the indentation now.
         --  has to be fixed later  ???
         --
         --  Xsprint.Indent := 0;

         Sprint_Node (Etbl_Tmp_1.Top_Node);
         Close_File;

         Etbl_Tmp_1 := Etbl_Tmp_1.Successor;
         Etbl_Tmp_2 := Main_Etbl;
         First      := True;
      end loop;
   end Write_Body_REQs;

   ---------------------
   -- Write_Spec_REQs --
   ---------------------

   procedure Write_Spec_REQs is
      Buffer : String (1 .. 100);
      Length : Integer;
      Found  : Boolean;

      Etbl_Tmp   : Entity_Table_Acc;

      procedure Open_File (I : Unit_Number_Type);
      --  Open file to write Spec_REQs

      procedure Close_File;
      --  Close the file after Spec_REQs are written

      procedure Open_File (I : Unit_Number_Type) is
      begin
         --  Here we build the file name of the Spec_REQ.
         --  The file name is the file name of the withed unit,
         --  the suffix changed from '.ads' into
         --  '.' & withing_unit_name & Spec_REQ_Suffix !

         Get_Name_String (File_Name (Source_Index (Main_Unit)));
         Buffer (1 .. Name_Len) := Name_Buffer (1 .. Name_Len);
         Length := Name_Len - 3;

         Get_Name_String (File_Name (Source_Index (I)));
         Name_Buffer (Name_Len + 1 .. Length + Name_Len) :=
            Buffer (1 .. Length);
         Length := Length + Name_Len - 4;

         Name_Buffer (Length + 1 .. Length + Spec_REQ_Suffix'Length)
           := Spec_REQ_Suffix;
         Name_Buffer (Length + Spec_REQ_Suffix'Length + 1) := Ascii.NUL;

         Create_Req_Output;
      end Open_File;

      procedure Close_File is
      begin
         Write_Eol;
         Set_Standard_Output;
         Close_Xref_Output;
      end Close_File;

   --  Start of processing for Write_Spec_REQs

   begin
      for J in Loaded_Files'Range loop

         if Loaded_Files (J).Create_REQ then

            --  First we mark all the entities which are used by the withed
            --  spec itself.

            Clear_And_Mark_Xrefs (Loaded_Files (J).Etbl,
              Loaded_Files (J).Etbl, True, False);

            --  Then we mark all the entities which are used by the main object
            --  (Main_Unit, all predecessors and all successors).

            Etbl_Tmp := Loaded_Files (Main_Unit).Etbl;
            while Etbl_Tmp /= null loop
               Clear_And_Mark_Xrefs
                 (Loaded_Files (J).Etbl, Etbl_Tmp, False, False);
               Etbl_Tmp := Etbl_Tmp.Predecessor;
            end loop;

            Etbl_Tmp := Loaded_Files (Main_Unit).Etbl.Successor;
            while Etbl_Tmp /= null loop
               Clear_And_Mark_Xrefs
                 (Loaded_Files (J).Etbl, Etbl_Tmp, False, False);
               Etbl_Tmp := Etbl_Tmp.Successor;
            end loop;

            --  Then remove the entities with no references step by step until
            --  all the remaining entities have one or more references. This
            --  must be done within a loop because after having removed some
            --  entities an earlier defined entity may become removable.

            Found := True;
            while Found loop
               Remove_Entities (Loaded_Files (J).Etbl, Found);
            end loop;

            Open_File (J);

            --  CC
            --  don't touch the indentation now.
            --  has to be fixed later  ???
            --  Xsprint.Indent := 0;

            Sprint_Node (Cunit (J));
            Close_File;
         end if;

      end loop;
   end Write_Spec_REQs;

   ----------------
   -- Write_Xref --
   ----------------

   procedure Write_Xref (The_Etbl : Entity_Table_Acc) is
      Etbl_Tmp     : Entity_Table_Acc := The_Etbl;
      Etbl_Scanned : Entity_Table_Acc;
      Xref_Filetyp : Xfiltyp;

   begin
      if Xref_Flag then

         --  File and warning messages output

         if Global_Xref_File then
            Xref_Filetyp := Xglobal;
         elsif Is_Body_Name (Unit_Name (Main_Unit)) then
            Xref_Filetyp := Xbody;
         else
            Xref_Filetyp := Xspec;
         end if;

         Create_Xref_Output (Xref_Filetyp);

         if Global_Xref_File then

            --  When we generate a complete Xref file then we scan
            --  all the entity table, but first do the requested units
            --  so that auxiliary units references will get marked.

            while Etbl_Tmp /= null loop
               if Etbl_Tmp.RU then
                  Writ (Etbl_Tmp, Full_Xref, False);
               end if;

               Etbl_Tmp := Etbl_Tmp.Next_Etbl;
            end loop;

            Etbl_Tmp := The_Etbl;
            while Etbl_Tmp /= null loop
               if not Etbl_Tmp.RU and then Etbl_Tmp.Status in Spec_Status then
                  Writ (Etbl_Tmp, Smart_Xref, False);
               end if;

               Etbl_Tmp := Etbl_Tmp.Next_Etbl;
            end loop;

            Close_Xref_Output;

         else
            --  Before writing any Informations in the xref file we write
            --  all the files names that have been loaded during the
            --  previous compilations

            Write_Version;

            for The_Units in Loaded_Files'Range loop
               Write_Files_Info (Loaded_Files (The_Units).Etbl);
            end loop;

            --  When we generate a .ref file for each amin file given in
            --  argument then we scan the main entity table and then all
            --  the successors and predecesssors which are required units.

            Writ (Etbl_Tmp, Full_Xref, True);
            Osint.Close_Xref_Output;

            Etbl_Scanned := Etbl_Tmp;
            while Etbl_Scanned.Predecessor /= null loop
               Etbl_Scanned := Etbl_Scanned.Predecessor;
            end loop;

            while Etbl_Scanned /= null loop
               if Etbl_Scanned.RU and then Etbl_Scanned /= Etbl_Tmp  then
                  Writ (Etbl_Scanned, Full_Xref, False);
               end if;

               Etbl_Scanned := Etbl_Scanned.Successor;
            end loop;

         end if;

      elsif With_Warnings or Entity_Warnings then

         --  Only warning messages output

         while Etbl_Tmp /= null loop
            if Etbl_Tmp.RU then
               Writ (Etbl_Tmp, Full_Only_Standout, False);
            end if;

            Etbl_Tmp := Etbl_Tmp.Next_Etbl;
         end loop;
      end if;

   end Write_Xref;

end Xref;