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 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723
|
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- L I B . X R E F --
-- --
-- B o d y --
-- --
-- Copyright (C) 1998-2024, 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 3, 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 COPYING3. If not, go to --
-- http://www.gnu.org/licenses for a complete copy of the license. --
-- --
-- GNAT was originally developed by the GNAT team at New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc. --
-- --
------------------------------------------------------------------------------
with Atree; use Atree;
with Csets; use Csets;
with Einfo; use Einfo;
with Einfo.Utils; use Einfo.Utils;
with Elists; use Elists;
with Errout; use Errout;
with Exp_Tss; use Exp_Tss;
with Lib.Util; use Lib.Util;
with Nlists; use Nlists;
with Opt; use Opt;
with Restrict; use Restrict;
with Rident; use Rident;
with Sem; use Sem;
with Sem_Aux; use Sem_Aux;
with Sem_Prag; use Sem_Prag;
with Sem_Util; use Sem_Util;
with Sem_Warn; use Sem_Warn;
with Sinfo; use Sinfo;
with Sinfo.Nodes; use Sinfo.Nodes;
with Sinfo.Utils; use Sinfo.Utils;
with Sinput; use Sinput;
with Snames; use Snames;
with Stringt; use Stringt;
with Stand; use Stand;
with Table; use Table;
with Warnsw; use Warnsw;
with GNAT.Heap_Sort_G;
with GNAT.HTable;
package body Lib.Xref is
------------------
-- Declarations --
------------------
-- The Xref table is used to record references. The Loc field is set
-- to No_Location for a definition entry.
subtype Xref_Entry_Number is Int;
type Xref_Key is record
-- These are the components of Xref_Entry that participate in hash
-- lookups.
Ent : Entity_Id;
-- Entity referenced (E parameter to Generate_Reference)
Loc : Source_Ptr;
-- Location of reference (Original_Location (Sloc field of N parameter
-- to Generate_Reference)). Set to No_Location for the case of a
-- defining occurrence.
Typ : Character;
-- Reference type (Typ param to Generate_Reference)
Eun : Unit_Number_Type;
-- Unit number corresponding to Ent
Lun : Unit_Number_Type;
-- Unit number corresponding to Loc. Value is undefined and not
-- referenced if Loc is set to No_Location.
-- The following components are only used for SPARK cross-references
Ref_Scope : Entity_Id;
-- Entity of the closest subprogram or package enclosing the reference
Ent_Scope : Entity_Id;
-- Entity of the closest subprogram or package enclosing the definition,
-- which should be located in the same file as the definition itself.
end record;
type Xref_Entry is record
Key : Xref_Key;
Ent_Scope_File : Unit_Number_Type;
-- File for entity Ent_Scope
Def : Source_Ptr;
-- Original source location for entity being referenced. Note that these
-- values are used only during the output process, they are not set when
-- the entries are originally built. This is because private entities
-- can be swapped when the initial call is made.
HTable_Next : Xref_Entry_Number;
-- For use only by Static_HTable
end record;
package Xrefs is new Table.Table (
Table_Component_Type => Xref_Entry,
Table_Index_Type => Xref_Entry_Number,
Table_Low_Bound => 1,
Table_Initial => Alloc.Xrefs_Initial,
Table_Increment => Alloc.Xrefs_Increment,
Table_Name => "Xrefs");
--------------
-- Xref_Set --
--------------
-- We keep a set of xref entries, in order to avoid inserting duplicate
-- entries into the above Xrefs table. An entry is in Xref_Set if and only
-- if it is in Xrefs.
Num_Buckets : constant := 2**16;
subtype Header_Num is Integer range 0 .. Num_Buckets - 1;
type Null_Type is null record;
pragma Unreferenced (Null_Type);
function Hash (F : Xref_Entry_Number) return Header_Num;
function Equal (F1, F2 : Xref_Entry_Number) return Boolean;
procedure HT_Set_Next (E : Xref_Entry_Number; Next : Xref_Entry_Number);
function HT_Next (E : Xref_Entry_Number) return Xref_Entry_Number;
function Get_Key (E : Xref_Entry_Number) return Xref_Entry_Number;
pragma Inline (Hash, Equal, HT_Set_Next, HT_Next, Get_Key);
package Xref_Set is new GNAT.HTable.Static_HTable (
Header_Num,
Element => Xref_Entry,
Elmt_Ptr => Xref_Entry_Number,
Null_Ptr => 0,
Set_Next => HT_Set_Next,
Next => HT_Next,
Key => Xref_Entry_Number,
Get_Key => Get_Key,
Hash => Hash,
Equal => Equal);
-----------------------------
-- SPARK Xrefs Information --
-----------------------------
package body SPARK_Specific is separate;
------------------------
-- Local Subprograms --
------------------------
procedure Add_Entry (Key : Xref_Key; Ent_Scope_File : Unit_Number_Type);
-- Add an entry to the tables of Xref_Entries, avoiding duplicates
procedure Generate_Prim_Op_References (Typ : Entity_Id);
-- For a tagged type, generate implicit references to its primitive
-- operations, for source navigation. This is done right before emitting
-- cross-reference information rather than at the freeze point of the type
-- in order to handle late bodies that are primitive operations.
function Lt (T1, T2 : Xref_Entry) return Boolean;
-- Order cross-references
---------------
-- Add_Entry --
---------------
procedure Add_Entry (Key : Xref_Key; Ent_Scope_File : Unit_Number_Type) is
begin
Xrefs.Increment_Last; -- tentative
Xrefs.Table (Xrefs.Last).Key := Key;
-- Set the entry in Xref_Set, and if newly set, keep the above
-- tentative increment.
if Xref_Set.Set_If_Not_Present (Xrefs.Last) then
Xrefs.Table (Xrefs.Last).Ent_Scope_File := Ent_Scope_File;
-- Leave Def and HTable_Next uninitialized
Set_Has_Xref_Entry (Key.Ent);
-- It was already in Xref_Set, so throw away the tentatively-added entry
else
Xrefs.Decrement_Last;
end if;
end Add_Entry;
-----------
-- Equal --
-----------
function Equal (F1, F2 : Xref_Entry_Number) return Boolean is
Result : constant Boolean :=
Xrefs.Table (F1).Key = Xrefs.Table (F2).Key;
begin
return Result;
end Equal;
-------------------------
-- Generate_Definition --
-------------------------
procedure Generate_Definition (E : Entity_Id) is
begin
pragma Assert (Nkind (E) in N_Entity);
-- Note that we do not test Xref_Entity_Letters here. It is too early
-- to do so, since we are often called before the entity is fully
-- constructed, so that the Ekind is still E_Void.
if Opt.Xref_Active
-- Definition must come from source
-- We make an exception for subprogram child units that have no spec.
-- For these we generate a subprogram declaration for library use,
-- and the corresponding entity does not come from source.
-- Nevertheless, all references will be attached to it and we have
-- to treat is as coming from user code.
and then (Comes_From_Source (E) or else Is_Child_Unit (E))
-- And must have a reasonable source location that is not
-- within an instance (all entities in instances are ignored)
and then Sloc (E) > No_Location
and then Instantiation_Location (Sloc (E)) = No_Location
-- And must be a non-internal name from the main source unit
and then In_Extended_Main_Source_Unit (E)
and then not Is_Internal_Name (Chars (E))
then
Add_Entry
((Ent => E,
Loc => No_Location,
Typ => ' ',
Eun => Get_Source_Unit (Original_Location (Sloc (E))),
Lun => No_Unit,
Ref_Scope => Empty,
Ent_Scope => Empty),
Ent_Scope_File => No_Unit);
if In_Inlined_Body then
Set_Referenced (E);
end if;
end if;
end Generate_Definition;
---------------------------------
-- Generate_Operator_Reference --
---------------------------------
procedure Generate_Operator_Reference
(N : Node_Id;
T : Entity_Id)
is
begin
if not In_Extended_Main_Source_Unit (N) then
return;
end if;
-- If the operator is not a Standard operator, then we generate a real
-- reference to the user defined operator.
if Sloc (Entity (N)) /= Standard_Location then
Generate_Reference (Entity (N), N);
-- A reference to an implicit inequality operator is also a reference
-- to the user-defined equality.
if Nkind (N) = N_Op_Ne
and then not Comes_From_Source (Entity (N))
and then Present (Corresponding_Equality (Entity (N)))
then
Generate_Reference (Corresponding_Equality (Entity (N)), N);
end if;
-- For the case of Standard operators, we mark the result type as
-- referenced. This ensures that in the case where we are using a
-- derived operator, we mark an entity of the unit that implicitly
-- defines this operator as used. Otherwise we may think that no entity
-- of the unit is used. The actual entity marked as referenced is the
-- first subtype, which is the relevant user defined entity.
-- Note: we only do this for operators that come from source. The
-- generated code sometimes reaches for entities that do not need to be
-- explicitly visible (for example, when we expand the code for
-- comparing two record objects, the fields of the record may not be
-- visible).
elsif Comes_From_Source (N) then
Set_Referenced (First_Subtype (T));
end if;
end Generate_Operator_Reference;
---------------------------------
-- Generate_Prim_Op_References --
---------------------------------
procedure Generate_Prim_Op_References (Typ : Entity_Id) is
Base_T : Entity_Id;
Prim : Elmt_Id;
Prim_List : Elist_Id;
begin
-- Handle subtypes of synchronized types
if Ekind (Typ) = E_Protected_Subtype
or else Ekind (Typ) = E_Task_Subtype
then
Base_T := Etype (Typ);
else
Base_T := Typ;
end if;
-- References to primitive operations are only relevant for tagged types
if not Is_Tagged_Type (Base_T)
or else Is_Class_Wide_Type (Base_T)
then
return;
end if;
-- Ada 2005 (AI-345): For synchronized types generate reference to the
-- wrapper that allow us to dispatch calls through their implemented
-- abstract interface types.
-- The check for Present here is to protect against previously reported
-- critical errors.
Prim_List := Primitive_Operations (Base_T);
if No (Prim_List) then
return;
end if;
Prim := First_Elmt (Prim_List);
while Present (Prim) loop
-- If the operation is derived, get the original for cross-reference
-- reference purposes (it is the original for which we want the xref
-- and for which the comes_from_source test must be performed).
Generate_Reference
(Typ, Ultimate_Alias (Node (Prim)), 'p', Set_Ref => False);
Next_Elmt (Prim);
end loop;
end Generate_Prim_Op_References;
------------------------
-- Generate_Reference --
------------------------
procedure Generate_Reference
(E : Entity_Id;
N : Node_Id;
Typ : Character := 'r';
Set_Ref : Boolean := True;
Force : Boolean := False)
is
Actual_Typ : Character := Typ;
Call : Node_Id;
Def : Source_Ptr;
Ent : Entity_Id;
Ent_Scope : Entity_Id;
Formal : Entity_Id;
Kind : Entity_Kind;
Nod : Node_Id;
Ref : Source_Ptr;
Ref_Scope : Entity_Id;
function Get_Through_Renamings (E : Entity_Id) return Entity_Id;
-- Get the enclosing entity through renamings, which may come from
-- source or from the translation of generic instantiations.
function OK_To_Set_Referenced return Boolean;
-- Returns True if the Referenced flag can be set. There are a few
-- exceptions where we do not want to set this flag, see body for
-- details of these exceptional cases.
---------------------------
-- Get_Through_Renamings --
---------------------------
function Get_Through_Renamings (E : Entity_Id) return Entity_Id is
begin
case Ekind (E) is
-- For subprograms we just need to check once if they are have a
-- Renamed_Entity, because Renamed_Entity is set transitively.
when Subprogram_Kind =>
declare
Renamed : constant Entity_Id := Renamed_Entity (E);
begin
if Present (Renamed) then
return Renamed;
else
return E;
end if;
end;
-- For objects we need to repeatedly call Renamed_Object, because
-- it is not transitive.
when Object_Kind =>
declare
Obj : Entity_Id := E;
begin
loop
pragma Assert (Present (Obj));
declare
Renamed : constant Entity_Id := Renamed_Object (Obj);
begin
if Present (Renamed) then
Obj := Get_Enclosing_Object (Renamed);
-- The renamed expression denotes a non-object,
-- e.g. function call, slicing of a function call,
-- pointer dereference, etc.
if No (Obj)
or else Ekind (Obj) = E_Enumeration_Literal
then
return Empty;
end if;
else
return Obj;
end if;
end;
end loop;
end;
when others =>
return E;
end case;
end Get_Through_Renamings;
---------------------------
-- OK_To_Set_Referenced --
---------------------------
function OK_To_Set_Referenced return Boolean is
P : Node_Id;
begin
-- A reference from a pragma Unreferenced or pragma Unmodified or
-- pragma Warnings does not cause the Referenced flag to be set.
-- This avoids silly warnings about things being referenced and
-- not assigned when the only reference is from the pragma.
if Nkind (N) = N_Identifier then
P := Parent (N);
if Nkind (P) = N_Pragma_Argument_Association then
P := Parent (P);
if Nkind (P) = N_Pragma then
if Pragma_Name_Unmapped (P) in Name_Warnings
| Name_Unmodified
| Name_Unreferenced
then
return False;
end if;
end if;
-- A reference to a formal in a named parameter association does
-- not make the formal referenced. Formals that are unused in the
-- subprogram body are properly flagged as such, even if calls
-- elsewhere use named notation.
elsif Nkind (P) = N_Parameter_Association
and then N = Selector_Name (P)
then
return False;
end if;
end if;
return True;
end OK_To_Set_Referenced;
-- Start of processing for Generate_Reference
begin
-- If Get_Ignore_Errors, then we are in Preanalyze_Without_Errors, and
-- we should not record cross references, because that will cause
-- duplicates when we call Analyze.
if Get_Ignore_Errors then
return;
end if;
-- May happen in case of severe errors
if Nkind (E) not in N_Entity then
return;
end if;
Find_Actual (N, Formal, Call);
if Present (Formal) then
Kind := Ekind (Formal);
else
Kind := E_Void;
end if;
-- Check for obsolescent reference to package ASCII. GNAT treats this
-- element of annex J specially since in practice, programs make a lot
-- of use of this feature, so we don't include it in the set of features
-- diagnosed when Warn_On_Obsolescent_Features mode is set. However we
-- are required to note it as a violation of the RM defined restriction.
if E = Standard_ASCII then
Check_Restriction (No_Obsolescent_Features, N);
end if;
-- Check for reference to entity marked with Is_Obsolescent
-- Note that we always allow obsolescent references in the compiler
-- itself and the run time, since we assume that we know what we are
-- doing in such cases. For example the calls in Ada.Characters.Handling
-- to its own obsolescent subprograms are just fine.
-- In any case we only generate warnings if we are in the extended main
-- source unit, and the entity itself is not in the extended main source
-- unit, since we assume the source unit itself knows what is going on
-- (and for sure we do not want silly warnings, e.g. on the end line of
-- an obsolescent procedure body).
if Is_Obsolescent (E)
and then not GNAT_Mode
and then not In_Extended_Main_Source_Unit (E)
and then In_Extended_Main_Source_Unit (N)
then
Check_Restriction (No_Obsolescent_Features, N);
if Warn_On_Obsolescent_Feature then
Output_Obsolescent_Entity_Warnings (N, E);
end if;
end if;
-- Warn if reference to Ada 2005 entity not in Ada 2005 mode. We only
-- detect real explicit references (modifications and references).
if Comes_From_Source (N)
and then Is_Ada_2005_Only (E)
and then Ada_Version < Ada_2005
and then Warn_On_Ada_2005_Compatibility
and then (Typ = 'm' or else Typ = 'r' or else Typ = 's')
then
Error_Msg_NE ("& is only defined in Ada 2005?y?", N, E);
end if;
-- Warn if reference to Ada 2012 entity not in Ada 2012 mode. We only
-- detect real explicit references (modifications and references).
if Comes_From_Source (N)
and then Is_Ada_2012_Only (E)
and then Ada_Version < Ada_2012
and then Warn_On_Ada_2012_Compatibility
and then (Typ = 'm' or else Typ = 'r')
then
Error_Msg_NE ("& is only defined in Ada 2012?y?", N, E);
end if;
-- Warn if reference to Ada 2022 entity not in Ada 2022 mode. We only
-- detect real explicit references (modifications and references).
if Comes_From_Source (N)
and then Is_Ada_2022_Only (E)
and then not Is_Subprogram (E)
and then Ada_Version < Ada_2022
and then Warn_On_Ada_2022_Compatibility
and then (Typ = 'm' or else Typ = 'r')
then
Error_Msg_NE ("& is only defined in Ada 2022?y?", N, E);
-- Error on static and dispatching calls to Ada 2022 subprograms that
-- require overriding if we are not in Ada 2022 mode (since overriding
-- was skipped); warn if the subprogram does not require overriding.
elsif Comes_From_Source (N)
and then Is_Ada_2022_Only (E)
and then Ada_Version < Ada_2022
and then Is_Subprogram (E)
and then (Typ = 'r' or else Typ = 's' or else Typ = 'R')
then
if Requires_Overriding (E) then
Error_Msg_NE
("& is only defined in Ada 2022 and requires overriding", N, E);
elsif Warn_On_Ada_2022_Compatibility then
Error_Msg_NE ("& is only defined in Ada 2022?y?", N, E);
end if;
end if;
-- Never collect references if not in main source unit. However, we omit
-- this test if Typ is 'e' or 'k', since these entries are structural,
-- and it is useful to have them in units that reference packages as
-- well as units that define packages. We also omit the test for the
-- case of 'p' since we want to include inherited primitive operations
-- from other packages.
-- We also omit this test is this is a body reference for a subprogram
-- instantiation. In this case the reference is to the generic body,
-- which clearly need not be in the main unit containing the instance.
-- For the same reason we accept an implicit reference generated for
-- a default in an instance.
-- We also set the referenced flag in a generic package that is not in
-- the main source unit, when the object is of a formal private type,
-- to warn in the instance if the corresponding type is not a fully
-- initialized type.
if not In_Extended_Main_Source_Unit (N) then
if Typ = 'e' or else
Typ = 'I' or else
Typ = 'p' or else
Typ = 'i' or else
Typ = 'k'
or else (Typ = 'b' and then Is_Generic_Instance (E))
-- Allow the generation of references to reads, writes and calls
-- in SPARK mode when the related context comes from an instance.
or else
(GNATprove_Mode
and then In_Extended_Main_Code_Unit (N)
and then (Typ = 'm' or else Typ = 'r' or else Typ = 's'))
then
null;
elsif In_Instance_Body
and then In_Extended_Main_Code_Unit (N)
and then Is_Generic_Type (Etype (E))
then
Set_Referenced (E);
return;
elsif Inside_A_Generic
and then Is_Object (E)
and then Is_Generic_Type (Etype (E))
then
Set_Referenced (E);
return;
else
return;
end if;
end if;
-- For reference type p, the entity must be in main source unit
if Typ = 'p' and then not In_Extended_Main_Source_Unit (E) then
return;
end if;
-- Unless the reference is forced, we ignore references where the
-- reference itself does not come from source.
if not Force and then not Comes_From_Source (N) then
return;
end if;
-- Deal with setting entity as referenced, unless suppressed. Note that
-- we still do Set_Referenced on entities that do not come from source.
-- This situation arises when we have a source reference to a derived
-- operation, where the derived operation itself does not come from
-- source, but we still want to mark it as referenced, since we really
-- are referencing an entity in the corresponding package (this avoids
-- wrong complaints that the package contains no referenced entities).
if Set_Ref then
-- When E itself is an IN OUT parameter mark it referenced
if Is_Assignable (E)
and then Ekind (E) = E_In_Out_Parameter
and then Known_To_Be_Assigned (N)
then
Set_Referenced (E);
-- For the case where the entity is on the left hand side of an
-- assignment statement, we do nothing here.
-- The processing for Analyze_Assignment_Statement will set the
-- Referenced_As_LHS flag.
elsif Is_Assignable (E)
and then Known_To_Be_Assigned (N, Only_LHS => True)
then
null;
-- For objects that are renamings, just set as simply referenced.
-- We do not try to do assignment type tracking in this case.
elsif Is_Assignable (E)
and then Present (Renamed_Object (E))
then
Set_Referenced (E);
-- Check for a reference in a pragma that should not count as a
-- making the variable referenced for warning purposes.
elsif Is_Non_Significant_Pragma_Reference (N) then
null;
-- A reference in an attribute definition clause does not count as a
-- reference except for the case of Address. The reason that 'Address
-- is an exception is that it creates an alias through which the
-- variable may be referenced.
elsif Nkind (Parent (N)) = N_Attribute_Definition_Clause
and then Chars (Parent (N)) /= Name_Address
and then N = Name (Parent (N))
then
null;
-- Constant completion does not count as a reference
elsif Typ = 'c'
and then Ekind (E) = E_Constant
then
null;
-- Record representation clause does not count as a reference
elsif Nkind (N) = N_Identifier
and then Nkind (Parent (N)) = N_Record_Representation_Clause
then
null;
-- Discriminants do not need to produce a reference to record type
elsif Typ = 'd'
and then Nkind (Parent (N)) = N_Discriminant_Specification
then
null;
-- Out parameter case
elsif Kind = E_Out_Parameter
and then Is_Assignable (E)
then
-- If warning mode for all out parameters is set, or this is
-- the only warning parameter, then we want to mark this for
-- later warning logic by setting Referenced_As_Out_Parameter
if Warn_On_Modified_As_Out_Parameter (Formal) then
Set_Referenced_As_Out_Parameter (E, True);
Set_Referenced_As_LHS (E, False);
-- For OUT parameter not covered by the above cases, we simply
-- regard it as a reference.
else
Set_Referenced_As_Out_Parameter (E);
Set_Referenced (E);
end if;
-- Special processing for IN OUT parameters, where we have an
-- implicit assignment to a simple variable.
elsif Kind = E_In_Out_Parameter
and then Is_Assignable (E)
then
-- We count it as a read reference unless we're calling a
-- type support subprogram such as deep finalize.
if not Is_Entity_Name (Name (Call))
or else Get_TSS_Name (Entity (Name (Call))) = TSS_Null
then
Set_Referenced (E);
Set_Last_Assignment (E, Empty);
end if;
-- We count it as being referenced as an out parameter if the
-- option is set to warn on all out parameters, except that we
-- have a special exclusion for an intrinsic subprogram, which
-- is most likely an instantiation of Unchecked_Deallocation
-- which we do not want to consider as an assignment since it
-- generates false positives. We also exclude the case of an
-- IN OUT parameter if the name of the procedure is Free,
-- since we suspect similar semantics.
if Warn_On_All_Unread_Out_Parameters
and then Is_Entity_Name (Name (Call))
and then not Is_Intrinsic_Subprogram (Entity (Name (Call)))
and then Chars (Name (Call)) /= Name_Free
then
Set_Referenced_As_Out_Parameter (E, True);
Set_Referenced_As_LHS (E, False);
end if;
-- Don't count a recursive reference within a subprogram as a
-- reference (that allows detection of a recursive subprogram
-- whose only references are recursive calls as unreferenced).
elsif Is_Subprogram (E)
and then E = Nearest_Dynamic_Scope (Current_Scope)
then
null;
-- Any other occurrence counts as referencing the entity
elsif OK_To_Set_Referenced then
Set_Referenced (E);
-- If variable, this is an OK reference after an assignment
-- so we can clear the Last_Assignment indication.
if Is_Assignable (E) then
Set_Last_Assignment (E, Empty);
end if;
end if;
-- Check for pragma Unreferenced given and reference is within
-- this source unit (occasion for possible warning to be issued).
-- Note that the entity may be marked as unreferenced by pragma
-- Unused.
if Has_Unreferenced (E)
and then In_Same_Extended_Unit (E, N)
then
-- A reference as a named parameter in a call does not count as a
-- violation of pragma Unreferenced for this purpose.
if Nkind (N) = N_Identifier
and then Nkind (Parent (N)) = N_Parameter_Association
and then Selector_Name (Parent (N)) = N
then
null;
-- Neither does a reference to a variable on the left side of
-- an assignment or use of an out parameter with warnings for
-- unread out parameters specified (via -gnatw.o).
-- The reason for treating unread out parameters in a special
-- way is so that when pragma Unreferenced is specified on such
-- an out parameter we do not want to issue a warning about the
-- pragma being unnecessary - because the purpose of the flag
-- is to warn about them not being read (e.g. unreferenced)
-- after use.
elsif (Known_To_Be_Assigned (N, Only_LHS => True)
or else (Present (Formal)
and then Ekind (Formal) = E_Out_Parameter
and then Warn_On_All_Unread_Out_Parameters))
and then not (Ekind (E) = E_In_Out_Parameter
and then Known_To_Be_Assigned (N))
then
null;
-- Do not consider F'Result as a violation of pragma Unreferenced
-- since the attribute acts as an anonymous alias of the function
-- result and not as a real reference to the function.
elsif Ekind (E) in E_Function | E_Generic_Function
and then Is_Entity_Name (N)
and then Is_Attribute_Result (Parent (N))
then
null;
-- No warning if the reference is in a call that does not come
-- from source (e.g. a call to a controlled type primitive).
elsif not Comes_From_Source (Parent (N))
and then Nkind (Parent (N)) = N_Procedure_Call_Statement
then
null;
-- For entry formals, we want to place the warning message on the
-- corresponding entity in the accept statement. The current scope
-- is the body of the accept, so we find the formal whose name
-- matches that of the entry formal (there is no link between the
-- two entities, and the one in the accept statement is only used
-- for conformance checking).
elsif Ekind (Scope (E)) = E_Entry then
declare
BE : Entity_Id;
begin
BE := First_Entity (Current_Scope);
while Present (BE) loop
if Chars (BE) = Chars (E) then
if Has_Pragma_Unused (E) then
Error_Msg_NE -- CODEFIX
("??aspect Unused specified for&!", N, BE);
else
Error_Msg_NE -- CODEFIX
("??aspect Unreferenced specified for&!", N, BE);
end if;
exit;
end if;
Next_Entity (BE);
end loop;
end;
-- Here we issue the warning, since this is a real reference
elsif Has_Pragma_Unused (E) then
Error_Msg_NE -- CODEFIX
("??aspect Unused specified for&!", N, E);
else
Error_Msg_NE -- CODEFIX
("??aspect Unreferenced specified for&!", N, E);
end if;
end if;
-- If this is a subprogram instance, mark as well the internal
-- subprogram in the wrapper package, which may be a visible
-- compilation unit.
if Is_Overloadable (E)
and then Is_Generic_Instance (E)
and then Present (Alias (E))
then
Set_Referenced (Alias (E));
end if;
end if;
-- Generate reference if all conditions are met:
if
-- Cross referencing must be active
Opt.Xref_Active
-- The entity must be one for which we collect references
and then Xref_Entity_Letters (Ekind (E)) /= ' '
-- Both Sloc values must be set to something sensible
and then Sloc (E) > No_Location
and then Sloc (N) > No_Location
-- Ignore references from within an instance. The only exceptions to
-- this are default subprograms, for which we generate an implicit
-- reference and compilations in SPARK mode.
and then
(Instantiation_Location (Sloc (N)) = No_Location
or else Typ = 'i'
or else GNATprove_Mode)
-- Ignore dummy references
and then Typ /= ' '
then
if Nkind (N) in N_Identifier
| N_Defining_Identifier
| N_Defining_Operator_Symbol
| N_Operator_Symbol
| N_Defining_Character_Literal
| N_Op
or else (Nkind (N) = N_Character_Literal
and then Sloc (Entity (N)) /= Standard_Location)
then
Nod := N;
elsif Nkind (N) in N_Expanded_Name | N_Selected_Component then
Nod := Selector_Name (N);
else
return;
end if;
-- Normal case of source entity comes from source
if Comes_From_Source (E) then
Ent := E;
-- Because a declaration may be generated for a subprogram body
-- without declaration in GNATprove mode, for inlining, some
-- parameters may end up being marked as not coming from source
-- although they are. Take these into account specially.
elsif GNATprove_Mode and then Is_Formal (E) then
Ent := E;
-- Entity does not come from source, but is a derived subprogram and
-- the derived subprogram comes from source (after one or more
-- derivations) in which case the reference is to parent subprogram.
elsif Is_Overloadable (E)
and then Present (Alias (E))
then
Ent := Alias (E);
while not Comes_From_Source (Ent) loop
if No (Alias (Ent)) then
return;
end if;
Ent := Alias (Ent);
end loop;
-- The internally created defining entity for a child subprogram
-- that has no previous spec has valid references.
elsif Is_Overloadable (E)
and then Is_Child_Unit (E)
then
Ent := E;
-- Ditto for the formals of such a subprogram
elsif Is_Overloadable (Scope (E))
and then Is_Child_Unit (Scope (E))
then
Ent := E;
-- Record components of discriminated subtypes or derived types must
-- be treated as references to the original component.
elsif Ekind (E) = E_Component
and then Comes_From_Source (Original_Record_Component (E))
then
Ent := Original_Record_Component (E);
-- If this is an expanded reference to a discriminant, recover the
-- original discriminant, which gets the reference.
elsif Ekind (E) = E_In_Parameter
and then Present (Discriminal_Link (E))
then
Ent := Discriminal_Link (E);
Set_Referenced (Ent);
-- Ignore reference to any other entity that is not from source
else
return;
end if;
-- In SPARK mode, consider the underlying entity renamed instead of
-- the renaming, which is needed to compute a valid set of effects
-- (reads, writes) for the enclosing subprogram.
if GNATprove_Mode then
Ent := Get_Through_Renamings (Ent);
-- If no enclosing object, then it could be a reference to any
-- location not tracked individually, like heap-allocated data.
-- Conservatively approximate this possibility by generating a
-- dereference, and return.
if No (Ent) then
if Actual_Typ = 'w' then
SPARK_Specific.Generate_Dereference (Nod, 'r');
SPARK_Specific.Generate_Dereference (Nod, 'w');
else
SPARK_Specific.Generate_Dereference (Nod, 'r');
end if;
return;
end if;
end if;
-- Record reference to entity
if Actual_Typ = 'p'
and then Is_Subprogram (Nod)
and then Present (Overridden_Operation (Nod))
then
Actual_Typ := 'P';
end if;
-- Comment needed here for special SPARK code ???
if GNATprove_Mode then
-- Ignore references to an entity which is a Part_Of single
-- concurrent object. Ideally we would prefer to add it as a
-- reference to the corresponding concurrent type, but it is quite
-- difficult (as such references are not currently added even for)
-- reads/writes of private protected components) and not worth the
-- effort.
if Ekind (Ent) in E_Abstract_State | E_Constant | E_Variable
and then Present (Encapsulating_State (Ent))
and then Is_Single_Concurrent_Object (Encapsulating_State (Ent))
then
return;
end if;
Ref := Sloc (Nod);
Def := Sloc (Ent);
Ref_Scope :=
SPARK_Specific.Enclosing_Subprogram_Or_Library_Package (Nod);
Ent_Scope :=
SPARK_Specific.Enclosing_Subprogram_Or_Library_Package (Ent);
-- Since we are reaching through renamings in SPARK mode, we may
-- end up with standard constants. Ignore those.
if Sloc (Ent_Scope) <= Standard_Location
or else Def <= Standard_Location
then
return;
end if;
Add_Entry
((Ent => Ent,
Loc => Ref,
Typ => Actual_Typ,
Eun => Get_Top_Level_Code_Unit (Def),
Lun => Get_Top_Level_Code_Unit (Ref),
Ref_Scope => Ref_Scope,
Ent_Scope => Ent_Scope),
Ent_Scope_File => Get_Top_Level_Code_Unit (Ent));
else
Ref := Original_Location (Sloc (Nod));
Def := Original_Location (Sloc (Ent));
-- If this is an operator symbol, skip the initial quote for
-- navigation purposes. This is not done for the end label,
-- where we want the actual position after the closing quote.
if Typ = 't' then
null;
elsif Nkind (N) = N_Defining_Operator_Symbol
or else Nkind (Nod) = N_Operator_Symbol
then
Ref := Ref + 1;
end if;
Add_Entry
((Ent => Ent,
Loc => Ref,
Typ => Actual_Typ,
Eun => Get_Source_Unit (Def),
Lun => Get_Source_Unit (Ref),
Ref_Scope => Empty,
Ent_Scope => Empty),
Ent_Scope_File => No_Unit);
-- Generate reference to the first private entity
if Typ = 'e'
and then Comes_From_Source (E)
and then Nkind (Ent) = N_Defining_Identifier
and then (Is_Package_Or_Generic_Package (Ent)
or else Is_Concurrent_Type (Ent))
and then Present (First_Private_Entity (E))
and then In_Extended_Main_Source_Unit (N)
then
-- Handle case in which the full-view and partial-view of the
-- first private entity are swapped.
declare
First_Private : Entity_Id := First_Private_Entity (E);
begin
if Is_Private_Type (First_Private)
and then Present (Full_View (First_Private))
then
First_Private := Full_View (First_Private);
end if;
Add_Entry
((Ent => Ent,
Loc => Sloc (First_Private),
Typ => 'E',
Eun => Get_Source_Unit (Def),
Lun => Get_Source_Unit (Ref),
Ref_Scope => Empty,
Ent_Scope => Empty),
Ent_Scope_File => No_Unit);
end;
end if;
end if;
end if;
end Generate_Reference;
-----------------------------------
-- Generate_Reference_To_Formals --
-----------------------------------
procedure Generate_Reference_To_Formals (E : Entity_Id) is
Formal : Entity_Id;
begin
if Is_Access_Subprogram_Type (E) then
Formal := First_Formal (Designated_Type (E));
else
Formal := First_Formal (E);
end if;
while Present (Formal) loop
if Ekind (Formal) = E_In_Parameter then
if Nkind (Parameter_Type (Parent (Formal))) = N_Access_Definition
then
Generate_Reference (E, Formal, '^', False);
else
Generate_Reference (E, Formal, '>', False);
end if;
elsif Ekind (Formal) = E_In_Out_Parameter then
Generate_Reference (E, Formal, '=', False);
else
Generate_Reference (E, Formal, '<', False);
end if;
Next_Formal (Formal);
end loop;
end Generate_Reference_To_Formals;
-------------------------------------------
-- Generate_Reference_To_Generic_Formals --
-------------------------------------------
procedure Generate_Reference_To_Generic_Formals (E : Entity_Id) is
Formal : Entity_Id;
begin
Formal := First_Entity (E);
while Present (Formal) loop
if Comes_From_Source (Formal) then
Generate_Reference (E, Formal, 'z', False);
end if;
Next_Entity (Formal);
end loop;
end Generate_Reference_To_Generic_Formals;
-------------
-- Get_Key --
-------------
function Get_Key (E : Xref_Entry_Number) return Xref_Entry_Number is
begin
return E;
end Get_Key;
----------
-- Hash --
----------
function Hash (F : Xref_Entry_Number) return Header_Num is
-- It is unlikely to have two references to the same entity at the same
-- source location, so the hash function depends only on the Ent and Loc
-- fields.
XE : Xref_Entry renames Xrefs.Table (F);
type M is mod 2**32;
H : constant M := 3 * M (XE.Key.Ent) + 5 * M (abs XE.Key.Loc);
-- It would be more natural to write:
--
-- H : constant M := 3 * M'Mod (XE.Key.Ent) + 5 * M'Mod (XE.Key.Loc);
--
-- But we can't use M'Mod, because it prevents bootstrapping with older
-- compilers. Loc can be negative, so we do "abs" before converting.
-- One day this can be cleaned up ???
begin
return Header_Num (H mod Num_Buckets);
end Hash;
-----------------
-- HT_Set_Next --
-----------------
procedure HT_Set_Next (E : Xref_Entry_Number; Next : Xref_Entry_Number) is
begin
Xrefs.Table (E).HTable_Next := Next;
end HT_Set_Next;
-------------
-- HT_Next --
-------------
function HT_Next (E : Xref_Entry_Number) return Xref_Entry_Number is
begin
return Xrefs.Table (E).HTable_Next;
end HT_Next;
----------------
-- Initialize --
----------------
procedure Initialize is
begin
Xrefs.Init;
end Initialize;
--------
-- Lt --
--------
function Lt (T1, T2 : Xref_Entry) return Boolean is
begin
-- First test: if entity is in different unit, sort by unit
if T1.Key.Eun /= T2.Key.Eun then
return Dependency_Num (T1.Key.Eun) < Dependency_Num (T2.Key.Eun);
-- Second test: within same unit, sort by entity Sloc
elsif T1.Def /= T2.Def then
return T1.Def < T2.Def;
-- Third test: sort definitions ahead of references
elsif T1.Key.Loc = No_Location then
return True;
elsif T2.Key.Loc = No_Location then
return False;
-- Fourth test: for same entity, sort by reference location unit
elsif T1.Key.Lun /= T2.Key.Lun then
return Dependency_Num (T1.Key.Lun) < Dependency_Num (T2.Key.Lun);
-- Fifth test: order of location within referencing unit
elsif T1.Key.Loc /= T2.Key.Loc then
return T1.Key.Loc < T2.Key.Loc;
-- Finally, for two locations at the same address, we prefer
-- the one that does NOT have the type 'r' so that a modification
-- or extension takes preference, when there are more than one
-- reference at the same location. As a result, in the case of
-- entities that are in-out actuals, the read reference follows
-- the modify reference.
else
return T2.Key.Typ = 'r';
end if;
end Lt;
-----------------------
-- Output_References --
-----------------------
procedure Output_References is
procedure Get_Type_Reference
(Ent : Entity_Id;
Tref : out Entity_Id;
Left : out Character;
Right : out Character);
-- Given an Entity_Id Ent, determines whether a type reference is
-- required. If so, Tref is set to the entity for the type reference
-- and Left and Right are set to the left/right brackets to be output
-- for the reference. If no type reference is required, then Tref is
-- set to Empty, and Left/Right are set to space.
procedure Output_Import_Export_Info (Ent : Entity_Id);
-- Output language and external name information for an interfaced
-- entity, using the format <language, external_name>.
------------------------
-- Get_Type_Reference --
------------------------
procedure Get_Type_Reference
(Ent : Entity_Id;
Tref : out Entity_Id;
Left : out Character;
Right : out Character)
is
Sav : Entity_Id;
begin
-- See if we have a type reference
Tref := Ent;
Left := '{';
Right := '}';
loop
Sav := Tref;
-- Processing for types
if Is_Type (Tref) then
-- Case of base type
if Base_Type (Tref) = Tref then
-- If derived, then get first subtype
if Tref /= Etype (Tref) then
Tref := First_Subtype (Etype (Tref));
-- Set brackets for derived type, but don't override
-- pointer case since the fact that something is a
-- pointer is more important.
if Left /= '(' then
Left := '<';
Right := '>';
end if;
-- If the completion of a private type is itself a derived
-- type, we need the parent of the full view.
elsif Is_Private_Type (Tref)
and then Present (Full_View (Tref))
and then Etype (Full_View (Tref)) /= Full_View (Tref)
then
Tref := Etype (Full_View (Tref));
if Left /= '(' then
Left := '<';
Right := '>';
end if;
-- If non-derived pointer, get directly designated type.
-- If the type has a full view, all references are on the
-- partial view that is seen first.
elsif Is_Access_Type (Tref) then
Tref := Directly_Designated_Type (Tref);
Left := '(';
Right := ')';
elsif Is_Private_Type (Tref)
and then Present (Full_View (Tref))
then
if Is_Access_Type (Full_View (Tref)) then
Tref := Directly_Designated_Type (Full_View (Tref));
Left := '(';
Right := ')';
-- If the full view is an array type, we also retrieve
-- the corresponding component type, because the ali
-- entry already indicates that this is an array.
elsif Is_Array_Type (Full_View (Tref)) then
Tref := Component_Type (Full_View (Tref));
Left := '(';
Right := ')';
end if;
-- If non-derived array, get component type. Skip component
-- type for case of String or Wide_String, saves worthwhile
-- space.
elsif Is_Array_Type (Tref)
and then Tref /= Standard_String
and then Tref /= Standard_Wide_String
then
Tref := Component_Type (Tref);
Left := '(';
Right := ')';
-- For other non-derived base types, nothing
else
exit;
end if;
-- For a subtype, go to ancestor subtype
else
Tref := Ancestor_Subtype (Tref);
-- If no ancestor subtype, go to base type
if No (Tref) then
Tref := Base_Type (Sav);
end if;
end if;
-- For objects, functions, enum literals, just get type from
-- Etype field.
elsif Is_Object (Tref)
or else Ekind (Tref) = E_Enumeration_Literal
or else Ekind (Tref) = E_Function
or else Ekind (Tref) = E_Operator
then
Tref := Etype (Tref);
-- Another special case: an object of a classwide type
-- initialized with a tag-indeterminate call gets a subtype
-- of the classwide type during expansion. See if the original
-- type in the declaration is named, and return it instead
-- of going to the root type. The expression may be a class-
-- wide function call whose result is on the secondary stack,
-- which forces the declaration to be rewritten as a renaming,
-- so examine the source declaration.
if Ekind (Tref) = E_Class_Wide_Subtype then
declare
Decl : constant Node_Id := Original_Node (Parent (Ent));
begin
if Nkind (Decl) = N_Object_Declaration
and then Is_Entity_Name
(Original_Node (Object_Definition (Decl)))
then
Tref :=
Entity (Original_Node (Object_Definition (Decl)));
end if;
end;
-- For a function that returns a class-wide type, Tref is
-- already correct.
elsif Is_Overloadable (Ent)
and then Is_Class_Wide_Type (Tref)
then
return;
end if;
-- For anything else, exit
else
exit;
end if;
-- Exit if no type reference, or we are stuck in some loop trying
-- to find the type reference, or if the type is standard void
-- type (the latter is an implementation artifact that should not
-- show up in the generated cross-references).
exit when No (Tref)
or else Tref = Sav
or else Tref = Standard_Void_Type;
-- If we have a usable type reference, return, otherwise keep
-- looking for something useful (we are looking for something
-- that either comes from source or standard)
if Sloc (Tref) = Standard_Location
or else Comes_From_Source (Tref)
then
-- If the reference is a subtype created for a generic actual,
-- go actual directly, the inner subtype is not user visible.
if Nkind (Parent (Tref)) = N_Subtype_Declaration
and then not Comes_From_Source (Parent (Tref))
and then
(Is_Wrapper_Package (Scope (Tref))
or else Is_Generic_Instance (Scope (Tref)))
then
Tref := First_Subtype (Base_Type (Tref));
end if;
return;
end if;
end loop;
-- If we fall through the loop, no type reference
Tref := Empty;
Left := ' ';
Right := ' ';
end Get_Type_Reference;
-------------------------------
-- Output_Import_Export_Info --
-------------------------------
procedure Output_Import_Export_Info (Ent : Entity_Id) is
Language_Name : Name_Id;
Conv : constant Convention_Id := Convention (Ent);
begin
-- Generate language name from convention
if Conv = Convention_C or else Conv in Convention_C_Variadic then
Language_Name := Name_C;
elsif Conv = Convention_CPP then
Language_Name := Name_CPP;
elsif Conv = Convention_Ada then
Language_Name := Name_Ada;
else
-- For the moment we ignore all other cases ???
return;
end if;
Write_Info_Char ('<');
Get_Unqualified_Name_String (Language_Name);
for J in 1 .. Name_Len loop
Write_Info_Char (Name_Buffer (J));
end loop;
if Present (Interface_Name (Ent)) then
Write_Info_Char (',');
String_To_Name_Buffer (Strval (Interface_Name (Ent)));
for J in 1 .. Name_Len loop
Write_Info_Char (Name_Buffer (J));
end loop;
end if;
Write_Info_Char ('>');
end Output_Import_Export_Info;
-- Start of processing for Output_References
begin
-- First we add references to the primitive operations of tagged types
-- declared in the main unit.
Handle_Prim_Ops : declare
Ent : Entity_Id;
begin
for J in 1 .. Xrefs.Last loop
Ent := Xrefs.Table (J).Key.Ent;
if Is_Type (Ent)
and then Is_Tagged_Type (Ent)
and then Is_Base_Type (Ent)
and then In_Extended_Main_Source_Unit (Ent)
then
Generate_Prim_Op_References (Ent);
end if;
end loop;
end Handle_Prim_Ops;
-- Before we go ahead and output the references we have a problem
-- that needs dealing with. So far we have captured things that are
-- definitely referenced by the main unit, or defined in the main
-- unit. That's because we don't want to clutter up the ali file
-- for this unit with definition lines for entities in other units
-- that are not referenced.
-- But there is a glitch. We may reference an entity in another unit,
-- and it may have a type reference to an entity that is not directly
-- referenced in the main unit, which may mean that there is no xref
-- entry for this entity yet in the list of references.
-- If we don't do something about this, we will end with an orphan type
-- reference, i.e. it will point to an entity that does not appear
-- within the generated references in the ali file. That is not good for
-- tools using the xref information.
-- To fix this, we go through the references adding definition entries
-- for any unreferenced entities that can be referenced in a type
-- reference. There is a recursion problem here, and that is dealt with
-- by making sure that this traversal also traverses any entries that
-- get added by the traversal.
Handle_Orphan_Type_References : declare
J : Nat;
Tref : Entity_Id;
Ent : Entity_Id;
L, R : Character;
pragma Warnings (Off, L);
pragma Warnings (Off, R);
procedure New_Entry (E : Entity_Id);
-- Make an additional entry into the Xref table for a type entity
-- that is related to the current entity (parent, type ancestor,
-- progenitor, etc.).
----------------
-- New_Entry --
----------------
procedure New_Entry (E : Entity_Id) is
begin
pragma Assert (Present (E));
if not Has_Xref_Entry (Implementation_Base_Type (E))
and then Sloc (E) > No_Location
then
Add_Entry
((Ent => E,
Loc => No_Location,
Typ => Character'First,
Eun => Get_Source_Unit (Original_Location (Sloc (E))),
Lun => No_Unit,
Ref_Scope => Empty,
Ent_Scope => Empty),
Ent_Scope_File => No_Unit);
end if;
end New_Entry;
-- Start of processing for Handle_Orphan_Type_References
begin
-- Note that this is not a for loop for a very good reason. The
-- processing of items in the table can add new items to the table,
-- and they must be processed as well.
J := 1;
while J <= Xrefs.Last loop
Ent := Xrefs.Table (J).Key.Ent;
-- Do not generate reference information for an ignored Ghost
-- entity because neither the entity nor its references will
-- appear in the final tree.
if Is_Ignored_Ghost_Entity (Ent) then
goto Orphan_Continue;
end if;
Get_Type_Reference (Ent, Tref, L, R);
if Present (Tref)
and then not Has_Xref_Entry (Tref)
and then Sloc (Tref) > No_Location
then
New_Entry (Tref);
if Is_Record_Type (Ent)
and then Present (Interfaces (Ent))
then
-- Add an entry for each one of the given interfaces
-- implemented by type Ent.
declare
Elmt : Elmt_Id := First_Elmt (Interfaces (Ent));
begin
while Present (Elmt) loop
New_Entry (Node (Elmt));
Next_Elmt (Elmt);
end loop;
end;
end if;
end if;
-- Collect inherited primitive operations that may be declared in
-- another unit and have no visible reference in the current one.
if Is_Type (Ent)
and then Is_Tagged_Type (Ent)
and then Is_Derived_Type (Ent)
and then Is_Base_Type (Ent)
and then In_Extended_Main_Source_Unit (Ent)
then
declare
Op_List : constant Elist_Id := Primitive_Operations (Ent);
Op : Elmt_Id;
Prim : Entity_Id;
function Parent_Op (E : Entity_Id) return Entity_Id;
-- Find original operation, which may be inherited through
-- several derivations.
function Parent_Op (E : Entity_Id) return Entity_Id is
Orig_Op : constant Entity_Id := Alias (E);
begin
if No (Orig_Op) then
return Empty;
elsif not Comes_From_Source (E)
and then not Has_Xref_Entry (Orig_Op)
and then Comes_From_Source (Orig_Op)
then
return Orig_Op;
else
return Parent_Op (Orig_Op);
end if;
end Parent_Op;
begin
Op := First_Elmt (Op_List);
while Present (Op) loop
Prim := Parent_Op (Node (Op));
if Present (Prim) then
Add_Entry
((Ent => Prim,
Loc => No_Location,
Typ => Character'First,
Eun => Get_Source_Unit (Sloc (Prim)),
Lun => No_Unit,
Ref_Scope => Empty,
Ent_Scope => Empty),
Ent_Scope_File => No_Unit);
end if;
Next_Elmt (Op);
end loop;
end;
end if;
<<Orphan_Continue>>
J := J + 1;
end loop;
end Handle_Orphan_Type_References;
-- Now we have all the references, including those for any embedded type
-- references, so we can sort them, and output them.
Output_Refs : declare
Nrefs : constant Nat := Xrefs.Last;
-- Number of references in table
Rnums : array (0 .. Nrefs) of Nat;
-- This array contains numbers of references in the Xrefs table.
-- This list is sorted in output order. The extra 0'th entry is
-- convenient for the call to sort. When we sort the table, we
-- move the entries in Rnums around, but we do not move the
-- original table entries.
Curxu : Unit_Number_Type;
-- Current xref unit
Curru : Unit_Number_Type;
-- Current reference unit for one entity
Curent : Entity_Id;
-- Current entity
Curnam : String (1 .. Name_Buffer'Length);
Curlen : Natural;
-- Simple name and length of current entity
Curdef : Source_Ptr;
-- Original source location for current entity
Crloc : Source_Ptr;
-- Current reference location
Ctyp : Character;
-- Entity type character
Prevt : Character;
-- reference kind of previous reference
Tref : Entity_Id;
-- Type reference
Rref : Node_Id;
-- Renaming reference
Trunit : Unit_Number_Type;
-- Unit number for type reference
function Lt (Op1, Op2 : Natural) return Boolean;
-- Comparison function for Sort call
function Name_Change (X : Entity_Id) return Boolean;
-- Determines if entity X has a different simple name from Curent
procedure Move (From : Natural; To : Natural);
-- Move procedure for Sort call
package Sorting is new GNAT.Heap_Sort_G (Move, Lt);
--------
-- Lt --
--------
function Lt (Op1, Op2 : Natural) return Boolean is
T1 : Xref_Entry renames Xrefs.Table (Rnums (Nat (Op1)));
T2 : Xref_Entry renames Xrefs.Table (Rnums (Nat (Op2)));
begin
return Lt (T1, T2);
end Lt;
----------
-- Move --
----------
procedure Move (From : Natural; To : Natural) is
begin
Rnums (Nat (To)) := Rnums (Nat (From));
end Move;
-----------------
-- Name_Change --
-----------------
-- Why a string comparison here??? Why not compare Name_Id values???
function Name_Change (X : Entity_Id) return Boolean is
begin
Get_Unqualified_Name_String (Chars (X));
if Name_Len /= Curlen then
return True;
else
return Name_Buffer (1 .. Curlen) /= Curnam (1 .. Curlen);
end if;
end Name_Change;
-- Start of processing for Output_Refs
begin
-- Capture the definition Sloc values. We delay doing this till now,
-- since at the time the reference or definition is made, private
-- types may be swapped, and the Sloc value may be incorrect. We
-- also set up the pointer vector for the sort.
-- For user-defined operators we need to skip the initial quote and
-- point to the first character of the name, for navigation purposes.
for J in 1 .. Nrefs loop
declare
E : constant Entity_Id := Xrefs.Table (J).Key.Ent;
Loc : constant Source_Ptr := Original_Location (Sloc (E));
begin
Rnums (J) := J;
if Nkind (E) = N_Defining_Operator_Symbol then
Xrefs.Table (J).Def := Loc + 1;
else
Xrefs.Table (J).Def := Loc;
end if;
end;
end loop;
-- Sort the references
Sorting.Sort (Integer (Nrefs));
-- Initialize loop through references
Curxu := No_Unit;
Curent := Empty;
Curdef := No_Location;
Curru := No_Unit;
Crloc := No_Location;
Prevt := 'm';
-- Loop to output references
for Refno in 1 .. Nrefs loop
Output_One_Ref : declare
Ent : Entity_Id;
XE : Xref_Entry renames Xrefs.Table (Rnums (Refno));
-- The current entry to be accessed
Left : Character;
Right : Character;
-- Used for {} or <> or () for type reference
procedure Check_Type_Reference
(Ent : Entity_Id;
List_Interface : Boolean;
Is_Component : Boolean := False);
-- Find whether there is a meaningful type reference for
-- Ent, and display it accordingly. If List_Interface is
-- true, then Ent is a progenitor interface of the current
-- type entity being listed. In that case list it as is,
-- without looking for a type reference for it. Flag is also
-- used for index types of an array type, where the caller
-- supplies the intended type reference. Is_Component serves
-- the same purpose, to display the component type of a
-- derived array type, for which only the parent type has
-- ben displayed so far.
procedure Output_Instantiation_Refs (Loc : Source_Ptr);
-- Recursive procedure to output instantiation references for
-- the given source ptr in [file|line[...]] form. No output
-- if the given location is not a generic template reference.
procedure Output_Overridden_Op (Old_E : Entity_Id);
-- For a subprogram that is overriding, display information
-- about the inherited operation that it overrides.
--------------------------
-- Check_Type_Reference --
--------------------------
procedure Check_Type_Reference
(Ent : Entity_Id;
List_Interface : Boolean;
Is_Component : Boolean := False)
is
begin
if List_Interface then
-- This is a progenitor interface of the type for which
-- xref information is being generated.
Tref := Ent;
Left := '<';
Right := '>';
-- The following is not documented in lib-xref.ads ???
elsif Is_Component then
Tref := Ent;
Left := '(';
Right := ')';
else
Get_Type_Reference (Ent, Tref, Left, Right);
end if;
if Present (Tref) then
-- Case of standard entity, output name
if Sloc (Tref) = Standard_Location then
Write_Info_Char (Left);
Write_Info_Name (Chars (Tref));
Write_Info_Char (Right);
-- Case of source entity, output location
else
Write_Info_Char (Left);
Trunit := Get_Source_Unit (Sloc (Tref));
if Trunit /= Curxu then
Write_Info_Nat (Dependency_Num (Trunit));
Write_Info_Char ('|');
end if;
Write_Info_Nat
(Int (Get_Logical_Line_Number (Sloc (Tref))));
declare
Ent : Entity_Id;
Ctyp : Character;
begin
Ent := Tref;
Ctyp := Xref_Entity_Letters (Ekind (Ent));
if Ctyp = '+'
and then Present (Full_View (Ent))
then
Ent := Underlying_Type (Ent);
if Present (Ent) then
Ctyp := Xref_Entity_Letters (Ekind (Ent));
end if;
end if;
Write_Info_Char (Ctyp);
end;
Write_Info_Nat
(Int (Get_Column_Number (Sloc (Tref))));
-- If the type comes from an instantiation, add the
-- corresponding info.
Output_Instantiation_Refs (Sloc (Tref));
Write_Info_Char (Right);
end if;
end if;
end Check_Type_Reference;
-------------------------------
-- Output_Instantiation_Refs --
-------------------------------
procedure Output_Instantiation_Refs (Loc : Source_Ptr) is
Iloc : constant Source_Ptr := Instantiation_Location (Loc);
Lun : Unit_Number_Type;
Cu : constant Unit_Number_Type := Curru;
begin
-- Nothing to do if this is not an instantiation
if Iloc = No_Location then
return;
end if;
-- Output instantiation reference
Write_Info_Char ('[');
Lun := Get_Source_Unit (Iloc);
if Lun /= Curru then
Curru := Lun;
Write_Info_Nat (Dependency_Num (Curru));
Write_Info_Char ('|');
end if;
Write_Info_Nat (Int (Get_Logical_Line_Number (Iloc)));
-- Recursive call to get nested instantiations
Output_Instantiation_Refs (Iloc);
-- Output final ] after call to get proper nesting
Write_Info_Char (']');
Curru := Cu;
return;
end Output_Instantiation_Refs;
--------------------------
-- Output_Overridden_Op --
--------------------------
procedure Output_Overridden_Op (Old_E : Entity_Id) is
Op : Entity_Id;
begin
-- The overridden operation has an implicit declaration
-- at the point of derivation. What we want to display
-- is the original operation, which has the actual body
-- (or abstract declaration) that is being overridden.
-- The overridden operation is not always set, e.g. when
-- it is a predefined operator.
if No (Old_E) then
return;
-- Follow alias chain if one is present
elsif Present (Alias (Old_E)) then
-- The subprogram may have been implicitly inherited
-- through several levels of derivation, so find the
-- ultimate (source) ancestor.
Op := Ultimate_Alias (Old_E);
-- Normal case of no alias present. We omit generated
-- primitives like tagged equality, that have no source
-- representation.
else
Op := Old_E;
end if;
if Present (Op)
and then Sloc (Op) /= Standard_Location
and then Comes_From_Source (Op)
then
declare
Loc : constant Source_Ptr := Sloc (Op);
Par_Unit : constant Unit_Number_Type :=
Get_Source_Unit (Loc);
begin
Write_Info_Char ('<');
if Par_Unit /= Curxu then
Write_Info_Nat (Dependency_Num (Par_Unit));
Write_Info_Char ('|');
end if;
Write_Info_Nat (Int (Get_Logical_Line_Number (Loc)));
Write_Info_Char ('p');
Write_Info_Nat (Int (Get_Column_Number (Loc)));
Write_Info_Char ('>');
end;
end if;
end Output_Overridden_Op;
-- Start of processing for Output_One_Ref
begin
Ent := XE.Key.Ent;
-- Do not generate reference information for an ignored Ghost
-- entity because neither the entity nor its references will
-- appear in the final tree.
if Is_Ignored_Ghost_Entity (Ent) then
goto Continue;
end if;
Ctyp := Xref_Entity_Letters (Ekind (Ent));
-- Skip reference if it is the only reference to an entity,
-- and it is an END line reference, and the entity is not in
-- the current extended source. This prevents junk entries
-- consisting only of packages with END lines, where no
-- entity from the package is actually referenced.
if XE.Key.Typ = 'e'
and then Ent /= Curent
and then (Refno = Nrefs
or else
Ent /= Xrefs.Table (Rnums (Refno + 1)).Key.Ent)
and then not In_Extended_Main_Source_Unit (Ent)
then
goto Continue;
end if;
-- For private type, get full view type
if Ctyp = '+'
and then Present (Full_View (XE.Key.Ent))
then
Ent := Underlying_Type (Ent);
if Present (Ent) then
Ctyp := Xref_Entity_Letters (Ekind (Ent));
end if;
end if;
-- Special exception for Boolean
if Ctyp = 'E' and then Is_Boolean_Type (Ent) then
Ctyp := 'B';
end if;
-- For variable reference, get corresponding type
if Ctyp = '*' then
Ent := Etype (XE.Key.Ent);
Ctyp := Fold_Lower (Xref_Entity_Letters (Ekind (Ent)));
-- If variable is private type, get full view type
if Ctyp = '+'
and then Present (Full_View (Etype (XE.Key.Ent)))
then
Ent := Underlying_Type (Etype (XE.Key.Ent));
if Present (Ent) then
Ctyp := Fold_Lower (Xref_Entity_Letters (Ekind (Ent)));
end if;
elsif Is_Generic_Type (Ent) then
-- If the type of the entity is a generic private type,
-- there is no usable full view, so retain the indication
-- that this is an object.
Ctyp := '*';
end if;
-- Special handling for access parameters and objects and
-- components of an anonymous access type.
if Ekind (Etype (XE.Key.Ent)) in
E_Anonymous_Access_Type
| E_Anonymous_Access_Subprogram_Type
| E_Anonymous_Access_Protected_Subprogram_Type
then
if Is_Formal (XE.Key.Ent)
or else
Ekind (XE.Key.Ent) in
E_Variable | E_Constant | E_Component
then
Ctyp := 'p';
end if;
-- Special handling for Boolean
elsif Ctyp = 'e' and then Is_Boolean_Type (Ent) then
Ctyp := 'b';
end if;
end if;
-- Special handling for abstract types and operations
if Is_Overloadable (XE.Key.Ent)
and then Is_Abstract_Subprogram (XE.Key.Ent)
then
if Ctyp = 'U' then
Ctyp := 'x'; -- Abstract procedure
elsif Ctyp = 'V' then
Ctyp := 'y'; -- Abstract function
end if;
elsif Is_Type (XE.Key.Ent)
and then Is_Abstract_Type (XE.Key.Ent)
then
if Is_Interface (XE.Key.Ent) then
Ctyp := 'h';
elsif Ctyp = 'R' then
Ctyp := 'H'; -- Abstract type
end if;
end if;
-- Only output reference if interesting type of entity
if Ctyp = ' '
-- Suppress references to object definitions, used for local
-- references.
or else XE.Key.Typ = 'D'
or else XE.Key.Typ = 'I'
-- Suppress self references, except for bodies that act as
-- specs.
or else (XE.Key.Loc = XE.Def
and then
(XE.Key.Typ /= 'b'
or else not Is_Subprogram (XE.Key.Ent)))
-- Also suppress definitions of body formals (we only
-- treat these as references, and the references were
-- separately recorded).
or else (Is_Formal (XE.Key.Ent)
and then Present (Spec_Entity (XE.Key.Ent)))
then
null;
else
-- Start new Xref section if new xref unit
if XE.Key.Eun /= Curxu then
if Write_Info_Col > 1 then
Write_Info_EOL;
end if;
Curxu := XE.Key.Eun;
Write_Info_Initiate ('X');
Write_Info_Char (' ');
Write_Info_Nat (Dependency_Num (XE.Key.Eun));
Write_Info_Char (' ');
Write_Info_Name
(Reference_Name (Source_Index (XE.Key.Eun)));
end if;
-- Start new Entity line if new entity. Note that we
-- consider two entities the same if they have the same
-- name and source location. This causes entities in
-- instantiations to be treated as though they referred
-- to the template.
if No (Curent)
or else
(XE.Key.Ent /= Curent
and then
(Name_Change (XE.Key.Ent) or else XE.Def /= Curdef))
then
Curent := XE.Key.Ent;
Curdef := XE.Def;
Get_Unqualified_Name_String (Chars (XE.Key.Ent));
Curlen := Name_Len;
Curnam (1 .. Curlen) := Name_Buffer (1 .. Curlen);
if Write_Info_Col > 1 then
Write_Info_EOL;
end if;
-- Write column number information
Write_Info_Nat (Int (Get_Logical_Line_Number (XE.Def)));
Write_Info_Char (Ctyp);
Write_Info_Nat (Int (Get_Column_Number (XE.Def)));
-- Write level information
Write_Level_Info : declare
function Is_Visible_Generic_Entity
(E : Entity_Id) return Boolean;
-- Check whether E is declared in the visible part
-- of a generic package. For source navigation
-- purposes, treat this as a visible entity.
function Is_Private_Record_Component
(E : Entity_Id) return Boolean;
-- Check whether E is a non-inherited component of a
-- private extension. Even if the enclosing record is
-- public, we want to treat the component as private
-- for navigation purposes.
---------------------------------
-- Is_Private_Record_Component --
---------------------------------
function Is_Private_Record_Component
(E : Entity_Id) return Boolean
is
S : constant Entity_Id := Scope (E);
begin
return
Ekind (E) = E_Component
and then Nkind (Declaration_Node (S)) =
N_Private_Extension_Declaration
and then Original_Record_Component (E) = E;
end Is_Private_Record_Component;
-------------------------------
-- Is_Visible_Generic_Entity --
-------------------------------
function Is_Visible_Generic_Entity
(E : Entity_Id) return Boolean
is
Par : Node_Id;
begin
-- The Present check here is an error defense
if Present (Scope (E))
and then Ekind (Scope (E)) /= E_Generic_Package
then
return False;
end if;
Par := Parent (E);
while Present (Par) loop
if
Nkind (Par) = N_Generic_Package_Declaration
then
-- Entity is a generic formal
return False;
elsif
Nkind (Parent (Par)) = N_Package_Specification
then
return
Is_List_Member (Par)
and then List_Containing (Par) =
Visible_Declarations (Parent (Par));
else
Par := Parent (Par);
end if;
end loop;
return False;
end Is_Visible_Generic_Entity;
-- Start of processing for Write_Level_Info
begin
if Is_Hidden (Curent)
or else Is_Private_Record_Component (Curent)
then
Write_Info_Char (' ');
elsif
Is_Public (Curent)
or else Is_Visible_Generic_Entity (Curent)
then
Write_Info_Char ('*');
else
Write_Info_Char (' ');
end if;
end Write_Level_Info;
-- Output entity name. We use the occurrence from the
-- actual source program at the definition point.
declare
Ent_Name : constant String :=
Exact_Source_Name (Sloc (XE.Key.Ent));
begin
for C in Ent_Name'Range loop
Write_Info_Char (Ent_Name (C));
end loop;
end;
-- See if we have a renaming reference
if Is_Object (XE.Key.Ent)
and then Present (Renamed_Object (XE.Key.Ent))
then
Rref := Renamed_Object (XE.Key.Ent);
elsif Is_Overloadable (XE.Key.Ent)
and then Nkind (Parent (Declaration_Node (XE.Key.Ent)))
= N_Subprogram_Renaming_Declaration
then
Rref := Name (Parent (Declaration_Node (XE.Key.Ent)));
elsif Ekind (XE.Key.Ent) = E_Package
and then Nkind (Declaration_Node (XE.Key.Ent)) =
N_Package_Renaming_Declaration
then
Rref := Name (Declaration_Node (XE.Key.Ent));
else
Rref := Empty;
end if;
if Present (Rref) then
if Nkind (Rref) = N_Expanded_Name then
Rref := Selector_Name (Rref);
end if;
if Nkind (Rref) = N_Identifier
or else Nkind (Rref) = N_Operator_Symbol
then
null;
-- For renamed array components, use the array name
-- for the renamed entity, which reflect the fact that
-- in general the whole array is aliased.
elsif Nkind (Rref) = N_Indexed_Component then
if Nkind (Prefix (Rref)) = N_Identifier then
Rref := Prefix (Rref);
elsif Nkind (Prefix (Rref)) = N_Expanded_Name then
Rref := Selector_Name (Prefix (Rref));
else
Rref := Empty;
end if;
else
Rref := Empty;
end if;
end if;
-- Write out renaming reference if we have one
if Present (Rref) then
Write_Info_Char ('=');
Write_Info_Nat
(Int (Get_Logical_Line_Number (Sloc (Rref))));
Write_Info_Char (':');
Write_Info_Nat
(Int (Get_Column_Number (Sloc (Rref))));
end if;
-- Indicate that the entity is in the unit of the current
-- xref section.
Curru := Curxu;
-- Write out information about generic parent, if entity
-- is an instance.
if Is_Generic_Instance (XE.Key.Ent) then
declare
Gen_Par : constant Entity_Id :=
Generic_Parent
(Specification
(Unit_Declaration_Node
(XE.Key.Ent)));
Loc : constant Source_Ptr := Sloc (Gen_Par);
Gen_U : constant Unit_Number_Type :=
Get_Source_Unit (Loc);
begin
Write_Info_Char ('[');
if Curru /= Gen_U then
Write_Info_Nat (Dependency_Num (Gen_U));
Write_Info_Char ('|');
end if;
Write_Info_Nat
(Int (Get_Logical_Line_Number (Loc)));
Write_Info_Char (']');
end;
end if;
-- See if we have a type reference and if so output
Check_Type_Reference (XE.Key.Ent, False);
-- Additional information for types with progenitors,
-- including synchronized tagged types.
declare
Typ : constant Entity_Id := XE.Key.Ent;
Elmt : Elmt_Id;
begin
if Is_Record_Type (Typ)
and then Present (Interfaces (Typ))
then
Elmt := First_Elmt (Interfaces (Typ));
elsif Is_Concurrent_Type (Typ)
and then Present (Corresponding_Record_Type (Typ))
and then Present (
Interfaces (Corresponding_Record_Type (Typ)))
then
Elmt :=
First_Elmt (
Interfaces (Corresponding_Record_Type (Typ)));
else
Elmt := No_Elmt;
end if;
while Present (Elmt) loop
Check_Type_Reference (Node (Elmt), True);
Next_Elmt (Elmt);
end loop;
end;
-- For array types, list index types as well. (This is
-- not C, indexes have distinct types).
if Is_Array_Type (XE.Key.Ent) then
declare
A_Typ : constant Entity_Id := XE.Key.Ent;
Indx : Node_Id;
begin
-- If this is a derived array type, we have
-- output the parent type, so add the component
-- type now.
if Is_Derived_Type (A_Typ) then
Check_Type_Reference
(Component_Type (A_Typ), False, True);
end if;
-- Add references to index types.
Indx := First_Index (XE.Key.Ent);
while Present (Indx) loop
Check_Type_Reference
(First_Subtype (Etype (Indx)), True);
Next_Index (Indx);
end loop;
end;
end if;
-- If the entity is an overriding operation, write info
-- on operation that was overridden.
if Is_Subprogram (XE.Key.Ent)
and then Present (Overridden_Operation (XE.Key.Ent))
then
Output_Overridden_Op
(Overridden_Operation (XE.Key.Ent));
end if;
-- End of processing for entity output
Crloc := No_Location;
end if;
-- Output the reference if it is not as the same location
-- as the previous one, or it is a read-reference that
-- indicates that the entity is an in-out actual in a call.
if XE.Key.Loc /= No_Location
and then
(XE.Key.Loc /= Crloc
or else (Prevt = 'm' and then XE.Key.Typ = 'r'))
then
Crloc := XE.Key.Loc;
Prevt := XE.Key.Typ;
-- Start continuation if line full, else blank
if Write_Info_Col > 72 then
Write_Info_EOL;
Write_Info_Initiate ('.');
end if;
Write_Info_Char (' ');
-- Output file number if changed
if XE.Key.Lun /= Curru then
Curru := XE.Key.Lun;
Write_Info_Nat (Dependency_Num (Curru));
Write_Info_Char ('|');
end if;
Write_Info_Nat
(Int (Get_Logical_Line_Number (XE.Key.Loc)));
Write_Info_Char (XE.Key.Typ);
if Is_Overloadable (XE.Key.Ent) then
if (Is_Imported (XE.Key.Ent) and then XE.Key.Typ = 'b')
or else
(Is_Exported (XE.Key.Ent) and then XE.Key.Typ = 'i')
then
Output_Import_Export_Info (XE.Key.Ent);
end if;
end if;
Write_Info_Nat (Int (Get_Column_Number (XE.Key.Loc)));
Output_Instantiation_Refs (Sloc (XE.Key.Ent));
end if;
end if;
end Output_One_Ref;
<<Continue>>
null;
end loop;
Write_Info_EOL;
end Output_Refs;
end Output_References;
-- Start of elaboration for Lib.Xref
begin
-- Reset is necessary because Elmt_Ptr does not default to Null_Ptr,
-- because it's not an access type.
Xref_Set.Reset;
end Lib.Xref;
|