* config/rs6000/rs6000.c (rs6000_option_override_internal): Do not
[official-gcc.git] / gcc / ada / lib-xref-alfa.adb
blobc9ab1e03b1013a34d4898691c0fa65c839337472
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- L I B . X R E F . A L F A --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2011-2012, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
20 -- --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
23 -- --
24 ------------------------------------------------------------------------------
26 with Alfa; use Alfa;
27 with Einfo; use Einfo;
28 with Nmake; use Nmake;
29 with Put_Alfa;
31 with GNAT.HTable;
33 separate (Lib.Xref)
34 package body Alfa is
36 ---------------------
37 -- Local Constants --
38 ---------------------
40 -- Table of Alfa_Entities, True for each entity kind used in Alfa
42 Alfa_Entities : constant array (Entity_Kind) of Boolean :=
43 (E_Constant => True,
44 E_Function => True,
45 E_In_Out_Parameter => True,
46 E_In_Parameter => True,
47 E_Loop_Parameter => True,
48 E_Operator => True,
49 E_Out_Parameter => True,
50 E_Procedure => True,
51 E_Variable => True,
52 others => False);
54 -- True for each reference type used in Alfa
56 Alfa_References : constant array (Character) of Boolean :=
57 ('m' => True,
58 'r' => True,
59 's' => True,
60 others => False);
62 type Entity_Hashed_Range is range 0 .. 255;
63 -- Size of hash table headers
65 ---------------------
66 -- Local Variables --
67 ---------------------
69 Heap : Entity_Id := Empty;
70 -- A special entity which denotes the heap object
72 package Drefs is new Table.Table (
73 Table_Component_Type => Xref_Entry,
74 Table_Index_Type => Xref_Entry_Number,
75 Table_Low_Bound => 1,
76 Table_Initial => Alloc.Drefs_Initial,
77 Table_Increment => Alloc.Drefs_Increment,
78 Table_Name => "Drefs");
79 -- Table of cross-references for reads and writes through explicit
80 -- dereferences, that are output as reads/writes to the special variable
81 -- "Heap". These references are added to the regular references when
82 -- computing Alfa cross-references.
84 -----------------------
85 -- Local Subprograms --
86 -----------------------
88 procedure Add_Alfa_File (Ubody, Uspec : Unit_Number_Type; Dspec : Nat);
89 -- Add file and corresponding scopes for unit to the tables Alfa_File_Table
90 -- and Alfa_Scope_Table. When two units are present for the same
91 -- compilation unit, as it happens for library-level instantiations of
92 -- generics, then Ubody /= Uspec, and all scopes are added to the same
93 -- Alfa file. Otherwise Ubody = Uspec.
95 procedure Add_Alfa_Scope (N : Node_Id);
96 -- Add scope N to the table Alfa_Scope_Table
98 procedure Add_Alfa_Xrefs;
99 -- Filter table Xrefs to add all references used in Alfa to the table
100 -- Alfa_Xref_Table.
102 procedure Detect_And_Add_Alfa_Scope (N : Node_Id);
103 -- Call Add_Alfa_Scope on scopes
105 function Entity_Hash (E : Entity_Id) return Entity_Hashed_Range;
106 -- Hash function for hash table
108 procedure Traverse_Declarations_Or_Statements
109 (L : List_Id;
110 Process : Node_Processing;
111 Inside_Stubs : Boolean);
112 procedure Traverse_Handled_Statement_Sequence
113 (N : Node_Id;
114 Process : Node_Processing;
115 Inside_Stubs : Boolean);
116 procedure Traverse_Package_Body
117 (N : Node_Id;
118 Process : Node_Processing;
119 Inside_Stubs : Boolean);
120 procedure Traverse_Package_Declaration
121 (N : Node_Id;
122 Process : Node_Processing;
123 Inside_Stubs : Boolean);
124 procedure Traverse_Subprogram_Body
125 (N : Node_Id;
126 Process : Node_Processing;
127 Inside_Stubs : Boolean);
128 -- Traverse corresponding construct, calling Process on all declarations
130 -------------------
131 -- Add_Alfa_File --
132 -------------------
134 procedure Add_Alfa_File (Ubody, Uspec : Unit_Number_Type; Dspec : Nat) is
135 File : constant Source_File_Index := Source_Index (Uspec);
136 From : Scope_Index;
138 File_Name : String_Ptr;
139 Unit_File_Name : String_Ptr;
141 begin
142 -- Source file could be inexistant as a result of an error, if option
143 -- gnatQ is used.
145 if File = No_Source_File then
146 return;
147 end if;
149 From := Alfa_Scope_Table.Last + 1;
151 -- Unit might not have an associated compilation unit, as seen in code
152 -- filling Sdep_Table in Write_ALI.
154 if Present (Cunit (Ubody)) then
155 Traverse_Compilation_Unit
156 (CU => Cunit (Ubody),
157 Process => Detect_And_Add_Alfa_Scope'Access,
158 Inside_Stubs => False);
159 end if;
161 -- When two units are present for the same compilation unit, as it
162 -- happens for library-level instantiations of generics, then add all
163 -- scopes to the same Alfa file.
165 if Ubody /= Uspec then
166 if Present (Cunit (Uspec)) then
167 Traverse_Compilation_Unit
168 (CU => Cunit (Uspec),
169 Process => Detect_And_Add_Alfa_Scope'Access,
170 Inside_Stubs => False);
171 end if;
172 end if;
174 -- Update scope numbers
176 declare
177 Scope_Id : Int;
178 begin
179 Scope_Id := 1;
180 for Index in From .. Alfa_Scope_Table.Last loop
181 declare
182 S : Alfa_Scope_Record renames Alfa_Scope_Table.Table (Index);
183 begin
184 S.Scope_Num := Scope_Id;
185 S.File_Num := Dspec;
186 Scope_Id := Scope_Id + 1;
187 end;
188 end loop;
189 end;
191 -- Remove those scopes previously marked for removal
193 declare
194 Scope_Id : Scope_Index;
196 begin
197 Scope_Id := From;
198 for Index in From .. Alfa_Scope_Table.Last loop
199 declare
200 S : Alfa_Scope_Record renames Alfa_Scope_Table.Table (Index);
201 begin
202 if S.Scope_Num /= 0 then
203 Alfa_Scope_Table.Table (Scope_Id) := S;
204 Scope_Id := Scope_Id + 1;
205 end if;
206 end;
207 end loop;
209 Alfa_Scope_Table.Set_Last (Scope_Id - 1);
210 end;
212 -- Make entry for new file in file table
214 Get_Name_String (Reference_Name (File));
215 File_Name := new String'(Name_Buffer (1 .. Name_Len));
217 -- For subunits, also retrieve the file name of the unit. Only do so if
218 -- unit has an associated compilation unit.
220 if Present (Cunit (Uspec))
221 and then Present (Cunit (Unit (File)))
222 and then Nkind (Unit (Cunit (Unit (File)))) = N_Subunit
223 then
224 Get_Name_String (Reference_Name (Main_Source_File));
225 Unit_File_Name := new String'(Name_Buffer (1 .. Name_Len));
226 end if;
228 Alfa_File_Table.Append (
229 (File_Name => File_Name,
230 Unit_File_Name => Unit_File_Name,
231 File_Num => Dspec,
232 From_Scope => From,
233 To_Scope => Alfa_Scope_Table.Last));
234 end Add_Alfa_File;
236 --------------------
237 -- Add_Alfa_Scope --
238 --------------------
240 procedure Add_Alfa_Scope (N : Node_Id) is
241 E : constant Entity_Id := Defining_Entity (N);
242 Loc : constant Source_Ptr := Sloc (E);
243 Typ : Character;
245 begin
246 -- Ignore scopes without a proper location
248 if Sloc (N) = No_Location then
249 return;
250 end if;
252 case Ekind (E) is
253 when E_Function | E_Generic_Function =>
254 Typ := 'V';
256 when E_Procedure | E_Generic_Procedure =>
257 Typ := 'U';
259 when E_Subprogram_Body =>
260 declare
261 Spec : Node_Id;
263 begin
264 Spec := Parent (E);
266 if Nkind (Spec) = N_Defining_Program_Unit_Name then
267 Spec := Parent (Spec);
268 end if;
270 if Nkind (Spec) = N_Function_Specification then
271 Typ := 'V';
272 else
273 pragma Assert
274 (Nkind (Spec) = N_Procedure_Specification);
275 Typ := 'U';
276 end if;
277 end;
279 when E_Package | E_Package_Body | E_Generic_Package =>
280 Typ := 'K';
282 when E_Void =>
283 -- Compilation of prj-attr.adb with -gnatn creates a node with
284 -- entity E_Void for the package defined at a-charac.ads16:13
286 -- ??? TBD
288 return;
290 when others =>
291 raise Program_Error;
292 end case;
294 -- File_Num and Scope_Num are filled later. From_Xref and To_Xref are
295 -- filled even later, but are initialized to represent an empty range.
297 Alfa_Scope_Table.Append (
298 (Scope_Name => new String'(Unique_Name (E)),
299 File_Num => 0,
300 Scope_Num => 0,
301 Spec_File_Num => 0,
302 Spec_Scope_Num => 0,
303 Line => Nat (Get_Logical_Line_Number (Loc)),
304 Stype => Typ,
305 Col => Nat (Get_Column_Number (Loc)),
306 From_Xref => 1,
307 To_Xref => 0,
308 Scope_Entity => E));
309 end Add_Alfa_Scope;
311 --------------------
312 -- Add_Alfa_Xrefs --
313 --------------------
315 procedure Add_Alfa_Xrefs is
316 function Entity_Of_Scope (S : Scope_Index) return Entity_Id;
317 -- Return the entity which maps to the input scope index
319 function Get_Entity_Type (E : Entity_Id) return Character;
320 -- Return a character representing the type of entity
322 function Is_Alfa_Reference
323 (E : Entity_Id;
324 Typ : Character) return Boolean;
325 -- Return whether entity reference E meets Alfa requirements. Typ is the
326 -- reference type.
328 function Is_Alfa_Scope (E : Entity_Id) return Boolean;
329 -- Return whether the entity or reference scope meets requirements for
330 -- being an Alfa scope.
332 function Is_Future_Scope_Entity
333 (E : Entity_Id;
334 S : Scope_Index) return Boolean;
335 -- Check whether entity E is in Alfa_Scope_Table at index S or higher
337 function Is_Global_Constant (E : Entity_Id) return Boolean;
338 -- Return True if E is a global constant for which we should ignore
339 -- reads in Alfa.
341 function Lt (Op1 : Natural; Op2 : Natural) return Boolean;
342 -- Comparison function for Sort call
344 procedure Move (From : Natural; To : Natural);
345 -- Move procedure for Sort call
347 procedure Update_Scope_Range
348 (S : Scope_Index;
349 From : Xref_Index;
350 To : Xref_Index);
351 -- Update the scope which maps to S with the new range From .. To
353 package Sorting is new GNAT.Heap_Sort_G (Move, Lt);
355 function Get_Scope_Num (N : Entity_Id) return Nat;
356 -- Return the scope number associated to entity N
358 procedure Set_Scope_Num (N : Entity_Id; Num : Nat);
359 -- Associate entity N to scope number Num
361 No_Scope : constant Nat := 0;
362 -- Initial scope counter
364 type Scope_Rec is record
365 Num : Nat;
366 Entity : Entity_Id;
367 end record;
368 -- Type used to relate an entity and a scope number
370 package Scopes is new GNAT.HTable.Simple_HTable
371 (Header_Num => Entity_Hashed_Range,
372 Element => Scope_Rec,
373 No_Element => (Num => No_Scope, Entity => Empty),
374 Key => Entity_Id,
375 Hash => Entity_Hash,
376 Equal => "=");
377 -- Package used to build a correspondance between entities and scope
378 -- numbers used in Alfa cross references.
380 Nrefs : Nat := Xrefs.Last;
381 -- Number of references in table. This value may get reset (reduced)
382 -- when we eliminate duplicate reference entries as well as references
383 -- not suitable for local cross-references.
385 Nrefs_Add : constant Nat := Drefs.Last;
386 -- Number of additional references which correspond to dereferences in
387 -- the source code.
389 Rnums : array (0 .. Nrefs + Nrefs_Add) of Nat;
390 -- This array contains numbers of references in the Xrefs table. This
391 -- list is sorted in output order. The extra 0'th entry is convenient
392 -- for the call to sort. When we sort the table, we move the entries in
393 -- Rnums around, but we do not move the original table entries.
395 ---------------------
396 -- Entity_Of_Scope --
397 ---------------------
399 function Entity_Of_Scope (S : Scope_Index) return Entity_Id is
400 begin
401 return Alfa_Scope_Table.Table (S).Scope_Entity;
402 end Entity_Of_Scope;
404 ---------------------
405 -- Get_Entity_Type --
406 ---------------------
408 function Get_Entity_Type (E : Entity_Id) return Character is
409 begin
410 case Ekind (E) is
411 when E_Out_Parameter => return '<';
412 when E_In_Out_Parameter => return '=';
413 when E_In_Parameter => return '>';
414 when others => return '*';
415 end case;
416 end Get_Entity_Type;
418 -------------------
419 -- Get_Scope_Num --
420 -------------------
422 function Get_Scope_Num (N : Entity_Id) return Nat is
423 begin
424 return Scopes.Get (N).Num;
425 end Get_Scope_Num;
427 -----------------------
428 -- Is_Alfa_Reference --
429 -----------------------
431 function Is_Alfa_Reference
432 (E : Entity_Id;
433 Typ : Character) return Boolean
435 begin
436 -- The only references of interest on callable entities are calls. On
437 -- non-callable entities, the only references of interest are reads
438 -- and writes.
440 if Ekind (E) in Overloadable_Kind then
441 return Typ = 's';
443 -- References to constant objects are not considered in Alfa section,
444 -- as these will be translated as constants in the intermediate
445 -- language for formal verification, and should therefore never
446 -- appear in frame conditions.
448 elsif Is_Constant_Object (E) then
449 return False;
451 -- Objects of Task type or protected type are not Alfa references
453 elsif Present (Etype (E))
454 and then Ekind (Etype (E)) in Concurrent_Kind
455 then
456 return False;
458 -- In all other cases, result is true for reference/modify cases,
459 -- and false for all other cases.
461 else
462 return Typ = 'r' or else Typ = 'm';
463 end if;
464 end Is_Alfa_Reference;
466 -------------------
467 -- Is_Alfa_Scope --
468 -------------------
470 function Is_Alfa_Scope (E : Entity_Id) return Boolean is
471 begin
472 return Present (E)
473 and then not Is_Generic_Unit (E)
474 and then Renamed_Entity (E) = Empty
475 and then Get_Scope_Num (E) /= No_Scope;
476 end Is_Alfa_Scope;
478 ----------------------------
479 -- Is_Future_Scope_Entity --
480 ----------------------------
482 function Is_Future_Scope_Entity
483 (E : Entity_Id;
484 S : Scope_Index) return Boolean
486 function Is_Past_Scope_Entity return Boolean;
487 -- Check whether entity E is in Alfa_Scope_Table at index strictly
488 -- lower than S.
490 --------------------------
491 -- Is_Past_Scope_Entity --
492 --------------------------
494 function Is_Past_Scope_Entity return Boolean is
495 begin
496 for Index in Alfa_Scope_Table.First .. S - 1 loop
497 if Alfa_Scope_Table.Table (Index).Scope_Entity = E then
498 declare
499 Dummy : constant Alfa_Scope_Record :=
500 Alfa_Scope_Table.Table (Index);
501 pragma Unreferenced (Dummy);
502 begin
503 return True;
504 end;
505 end if;
506 end loop;
508 return False;
509 end Is_Past_Scope_Entity;
511 -- Start of processing for Is_Future_Scope_Entity
513 begin
514 for Index in S .. Alfa_Scope_Table.Last loop
515 if Alfa_Scope_Table.Table (Index).Scope_Entity = E then
516 return True;
517 end if;
518 end loop;
520 -- If this assertion fails, this means that the scope which we are
521 -- looking for has been treated already, which reveals a problem in
522 -- the order of cross-references.
524 pragma Assert (not Is_Past_Scope_Entity);
526 return False;
527 end Is_Future_Scope_Entity;
529 ------------------------
530 -- Is_Global_Constant --
531 ------------------------
533 function Is_Global_Constant (E : Entity_Id) return Boolean is
534 begin
535 return Ekind (E) = E_Constant
536 and then Ekind_In (Scope (E), E_Package, E_Package_Body);
537 end Is_Global_Constant;
539 --------
540 -- Lt --
541 --------
543 function Lt (Op1, Op2 : Natural) return Boolean is
544 T1 : constant Xref_Entry := Xrefs.Table (Rnums (Nat (Op1)));
545 T2 : constant Xref_Entry := Xrefs.Table (Rnums (Nat (Op2)));
547 begin
548 -- First test: if entity is in different unit, sort by unit. Note:
549 -- that we use Ent_Scope_File rather than Eun, as Eun may refer to
550 -- the file where the generic scope is defined, which may differ from
551 -- the file where the enclosing scope is defined. It is the latter
552 -- which matters for a correct order here.
554 if T1.Ent_Scope_File /= T2.Ent_Scope_File then
555 return Dependency_Num (T1.Ent_Scope_File) <
556 Dependency_Num (T2.Ent_Scope_File);
558 -- Second test: within same unit, sort by location of the scope of
559 -- the entity definition.
561 elsif Get_Scope_Num (T1.Key.Ent_Scope) /=
562 Get_Scope_Num (T2.Key.Ent_Scope)
563 then
564 return Get_Scope_Num (T1.Key.Ent_Scope) <
565 Get_Scope_Num (T2.Key.Ent_Scope);
567 -- Third test: within same unit and scope, sort by location of
568 -- entity definition.
570 elsif T1.Def /= T2.Def then
571 return T1.Def < T2.Def;
573 else
574 -- Both entities must be equal at this point
576 pragma Assert (T1.Key.Ent = T2.Key.Ent);
578 -- Fourth test: if reference is in same unit as entity definition,
579 -- sort first.
581 if T1.Key.Lun /= T2.Key.Lun
582 and then T1.Ent_Scope_File = T1.Key.Lun
583 then
584 return True;
586 elsif T1.Key.Lun /= T2.Key.Lun
587 and then T2.Ent_Scope_File = T2.Key.Lun
588 then
589 return False;
591 -- Fifth test: if reference is in same unit and same scope as
592 -- entity definition, sort first.
594 elsif T1.Ent_Scope_File = T1.Key.Lun
595 and then T1.Key.Ref_Scope /= T2.Key.Ref_Scope
596 and then T1.Key.Ent_Scope = T1.Key.Ref_Scope
597 then
598 return True;
600 elsif T2.Ent_Scope_File = T2.Key.Lun
601 and then T1.Key.Ref_Scope /= T2.Key.Ref_Scope
602 and then T2.Key.Ent_Scope = T2.Key.Ref_Scope
603 then
604 return False;
606 -- Sixth test: for same entity, sort by reference location unit
608 elsif T1.Key.Lun /= T2.Key.Lun then
609 return Dependency_Num (T1.Key.Lun) <
610 Dependency_Num (T2.Key.Lun);
612 -- Seventh test: for same entity, sort by reference location scope
614 elsif Get_Scope_Num (T1.Key.Ref_Scope) /=
615 Get_Scope_Num (T2.Key.Ref_Scope)
616 then
617 return Get_Scope_Num (T1.Key.Ref_Scope) <
618 Get_Scope_Num (T2.Key.Ref_Scope);
620 -- Eighth test: order of location within referencing unit
622 elsif T1.Key.Loc /= T2.Key.Loc then
623 return T1.Key.Loc < T2.Key.Loc;
625 -- Finally, for two locations at the same address prefer the one
626 -- that does NOT have the type 'r', so that a modification or
627 -- extension takes preference, when there are more than one
628 -- reference at the same location. As a result, in the case of
629 -- entities that are in-out actuals, the read reference follows
630 -- the modify reference.
632 else
633 return T2.Key.Typ = 'r';
634 end if;
635 end if;
636 end Lt;
638 ----------
639 -- Move --
640 ----------
642 procedure Move (From : Natural; To : Natural) is
643 begin
644 Rnums (Nat (To)) := Rnums (Nat (From));
645 end Move;
647 -------------------
648 -- Set_Scope_Num --
649 -------------------
651 procedure Set_Scope_Num (N : Entity_Id; Num : Nat) is
652 begin
653 Scopes.Set (K => N, E => Scope_Rec'(Num => Num, Entity => N));
654 end Set_Scope_Num;
656 ------------------------
657 -- Update_Scope_Range --
658 ------------------------
660 procedure Update_Scope_Range
661 (S : Scope_Index;
662 From : Xref_Index;
663 To : Xref_Index)
665 begin
666 Alfa_Scope_Table.Table (S).From_Xref := From;
667 Alfa_Scope_Table.Table (S).To_Xref := To;
668 end Update_Scope_Range;
670 -- Local variables
672 Col : Nat;
673 From_Index : Xref_Index;
674 Line : Nat;
675 Loc : Source_Ptr;
676 Prev_Typ : Character;
677 Ref_Count : Nat;
678 Ref_Id : Entity_Id;
679 Ref_Name : String_Ptr;
680 Scope_Id : Scope_Index;
682 -- Start of processing for Add_Alfa_Xrefs
684 begin
685 for Index in Alfa_Scope_Table.First .. Alfa_Scope_Table.Last loop
686 declare
687 S : Alfa_Scope_Record renames Alfa_Scope_Table.Table (Index);
688 begin
689 Set_Scope_Num (S.Scope_Entity, S.Scope_Num);
690 end;
691 end loop;
693 -- Set up the pointer vector for the sort
695 for Index in 1 .. Nrefs loop
696 Rnums (Index) := Index;
697 end loop;
699 for Index in Drefs.First .. Drefs.Last loop
700 Xrefs.Append (Drefs.Table (Index));
702 Nrefs := Nrefs + 1;
703 Rnums (Nrefs) := Xrefs.Last;
704 end loop;
706 -- Capture the definition Sloc values. As in the case of normal cross
707 -- references, we have to wait until now to get the correct value.
709 for Index in 1 .. Nrefs loop
710 Xrefs.Table (Index).Def := Sloc (Xrefs.Table (Index).Key.Ent);
711 end loop;
713 -- Eliminate entries not appropriate for Alfa. Done prior to sorting
714 -- cross-references, as it discards useless references which do not have
715 -- a proper format for the comparison function (like no location).
717 Ref_Count := Nrefs;
718 Nrefs := 0;
720 for Index in 1 .. Ref_Count loop
721 declare
722 Ref : Xref_Key renames Xrefs.Table (Rnums (Index)).Key;
724 begin
725 if Alfa_Entities (Ekind (Ref.Ent))
726 and then Alfa_References (Ref.Typ)
727 and then Is_Alfa_Scope (Ref.Ent_Scope)
728 and then Is_Alfa_Scope (Ref.Ref_Scope)
729 and then not Is_Global_Constant (Ref.Ent)
730 and then Is_Alfa_Reference (Ref.Ent, Ref.Typ)
732 -- Discard references from unknown scopes, e.g. generic scopes
734 and then Get_Scope_Num (Ref.Ent_Scope) /= No_Scope
735 and then Get_Scope_Num (Ref.Ref_Scope) /= No_Scope
736 then
737 Nrefs := Nrefs + 1;
738 Rnums (Nrefs) := Rnums (Index);
739 end if;
740 end;
741 end loop;
743 -- Sort the references
745 Sorting.Sort (Integer (Nrefs));
747 -- Eliminate duplicate entries
749 -- We need this test for Ref_Count because if we force ALI file
750 -- generation in case of errors detected, it may be the case that
751 -- Nrefs is 0, so we should not reset it here.
753 if Nrefs >= 2 then
754 Ref_Count := Nrefs;
755 Nrefs := 1;
757 for Index in 2 .. Ref_Count loop
758 if Xrefs.Table (Rnums (Index)) /=
759 Xrefs.Table (Rnums (Nrefs))
760 then
761 Nrefs := Nrefs + 1;
762 Rnums (Nrefs) := Rnums (Index);
763 end if;
764 end loop;
765 end if;
767 -- Eliminate the reference if it is at the same location as the previous
768 -- one, unless it is a read-reference indicating that the entity is an
769 -- in-out actual in a call.
771 Ref_Count := Nrefs;
772 Nrefs := 0;
773 Loc := No_Location;
774 Prev_Typ := 'm';
776 for Index in 1 .. Ref_Count loop
777 declare
778 Ref : Xref_Key renames Xrefs.Table (Rnums (Index)).Key;
780 begin
781 if Ref.Loc /= Loc
782 or else (Prev_Typ = 'm' and then Ref.Typ = 'r')
783 then
784 Loc := Ref.Loc;
785 Prev_Typ := Ref.Typ;
786 Nrefs := Nrefs + 1;
787 Rnums (Nrefs) := Rnums (Index);
788 end if;
789 end;
790 end loop;
792 -- The two steps have eliminated all references, nothing to do
794 if Alfa_Scope_Table.Last = 0 then
795 return;
796 end if;
798 Ref_Id := Empty;
799 Scope_Id := 1;
800 From_Index := 1;
802 -- Loop to output references
804 for Refno in 1 .. Nrefs loop
805 declare
806 Ref_Entry : Xref_Entry renames Xrefs.Table (Rnums (Refno));
807 Ref : Xref_Key renames Ref_Entry.Key;
809 begin
810 -- If this assertion fails, the scope which we are looking for is
811 -- not in Alfa scope table, which reveals either a problem in the
812 -- construction of the scope table, or an erroneous scope for the
813 -- current cross-reference.
815 pragma Assert (Is_Future_Scope_Entity (Ref.Ent_Scope, Scope_Id));
817 -- Update the range of cross references to which the current scope
818 -- refers to. This may be the empty range only for the first scope
819 -- considered.
821 if Ref.Ent_Scope /= Entity_Of_Scope (Scope_Id) then
822 Update_Scope_Range
823 (S => Scope_Id,
824 From => From_Index,
825 To => Alfa_Xref_Table.Last);
827 From_Index := Alfa_Xref_Table.Last + 1;
828 end if;
830 while Ref.Ent_Scope /= Entity_Of_Scope (Scope_Id) loop
831 Scope_Id := Scope_Id + 1;
832 pragma Assert (Scope_Id <= Alfa_Scope_Table.Last);
833 end loop;
835 if Ref.Ent /= Ref_Id then
836 Ref_Name := new String'(Unique_Name (Ref.Ent));
837 end if;
839 if Ref.Ent = Heap then
840 Line := 0;
841 Col := 0;
842 else
843 Line := Int (Get_Logical_Line_Number (Ref_Entry.Def));
844 Col := Int (Get_Column_Number (Ref_Entry.Def));
845 end if;
847 Alfa_Xref_Table.Append (
848 (Entity_Name => Ref_Name,
849 Entity_Line => Line,
850 Etype => Get_Entity_Type (Ref.Ent),
851 Entity_Col => Col,
852 File_Num => Dependency_Num (Ref.Lun),
853 Scope_Num => Get_Scope_Num (Ref.Ref_Scope),
854 Line => Int (Get_Logical_Line_Number (Ref.Loc)),
855 Rtype => Ref.Typ,
856 Col => Int (Get_Column_Number (Ref.Loc))));
857 end;
858 end loop;
860 -- Update the range of cross references to which the scope refers to
862 Update_Scope_Range
863 (S => Scope_Id,
864 From => From_Index,
865 To => Alfa_Xref_Table.Last);
866 end Add_Alfa_Xrefs;
868 ------------------
869 -- Collect_Alfa --
870 ------------------
872 procedure Collect_Alfa (Sdep_Table : Unit_Ref_Table; Num_Sdep : Nat) is
873 D1 : Nat;
874 D2 : Nat;
876 begin
877 -- Cross-references should have been computed first
879 pragma Assert (Xrefs.Last /= 0);
881 Initialize_Alfa_Tables;
883 -- Generate file and scope Alfa information
885 D1 := 1;
886 while D1 <= Num_Sdep loop
888 -- In rare cases, when treating the library-level instantiation of a
889 -- generic, two consecutive units refer to the same compilation unit
890 -- node and entity. In that case, treat them as a single unit for the
891 -- sake of Alfa cross references by passing to Add_Alfa_File.
893 if D1 < Num_Sdep
894 and then Cunit_Entity (Sdep_Table (D1)) =
895 Cunit_Entity (Sdep_Table (D1 + 1))
896 then
897 D2 := D1 + 1;
898 else
899 D2 := D1;
900 end if;
902 Add_Alfa_File
903 (Ubody => Sdep_Table (D1),
904 Uspec => Sdep_Table (D2),
905 Dspec => D2);
906 D1 := D2 + 1;
907 end loop;
909 -- Fill in the spec information when relevant
911 declare
912 package Entity_Hash_Table is new
913 GNAT.HTable.Simple_HTable
914 (Header_Num => Entity_Hashed_Range,
915 Element => Scope_Index,
916 No_Element => 0,
917 Key => Entity_Id,
918 Hash => Entity_Hash,
919 Equal => "=");
921 begin
922 -- Fill in the hash-table
924 for S in Alfa_Scope_Table.First .. Alfa_Scope_Table.Last loop
925 declare
926 Srec : Alfa_Scope_Record renames Alfa_Scope_Table.Table (S);
927 begin
928 Entity_Hash_Table.Set (Srec.Scope_Entity, S);
929 end;
930 end loop;
932 -- Use the hash-table to locate spec entities
934 for S in Alfa_Scope_Table.First .. Alfa_Scope_Table.Last loop
935 declare
936 Srec : Alfa_Scope_Record renames Alfa_Scope_Table.Table (S);
938 Spec_Entity : constant Entity_Id :=
939 Unique_Entity (Srec.Scope_Entity);
940 Spec_Scope : constant Scope_Index :=
941 Entity_Hash_Table.Get (Spec_Entity);
943 begin
944 -- Generic spec may be missing in which case Spec_Scope is zero
946 if Spec_Entity /= Srec.Scope_Entity
947 and then Spec_Scope /= 0
948 then
949 Srec.Spec_File_Num :=
950 Alfa_Scope_Table.Table (Spec_Scope).File_Num;
951 Srec.Spec_Scope_Num :=
952 Alfa_Scope_Table.Table (Spec_Scope).Scope_Num;
953 end if;
954 end;
955 end loop;
956 end;
958 -- Generate cross reference Alfa information
960 Add_Alfa_Xrefs;
961 end Collect_Alfa;
963 -------------------------------
964 -- Detect_And_Add_Alfa_Scope --
965 -------------------------------
967 procedure Detect_And_Add_Alfa_Scope (N : Node_Id) is
968 begin
969 if Nkind_In (N, N_Subprogram_Declaration,
970 N_Subprogram_Body,
971 N_Subprogram_Body_Stub,
972 N_Package_Declaration,
973 N_Package_Body)
974 then
975 Add_Alfa_Scope (N);
976 end if;
977 end Detect_And_Add_Alfa_Scope;
979 -------------------------------------
980 -- Enclosing_Subprogram_Or_Package --
981 -------------------------------------
983 function Enclosing_Subprogram_Or_Package (N : Node_Id) return Entity_Id is
984 Result : Entity_Id;
986 begin
987 -- If N is the defining identifier for a subprogram, then return the
988 -- enclosing subprogram or package, not this subprogram.
990 if Nkind_In (N, N_Defining_Identifier, N_Defining_Operator_Symbol)
991 and then Nkind (Parent (N)) in N_Subprogram_Specification
992 then
993 Result := Parent (Parent (Parent (N)));
994 else
995 Result := N;
996 end if;
998 while Present (Result) loop
999 case Nkind (Result) is
1000 when N_Package_Specification =>
1001 Result := Defining_Unit_Name (Result);
1002 exit;
1004 when N_Package_Body =>
1005 Result := Defining_Unit_Name (Result);
1006 exit;
1008 when N_Subprogram_Specification =>
1009 Result := Defining_Unit_Name (Result);
1010 exit;
1012 when N_Subprogram_Declaration =>
1013 Result := Defining_Unit_Name (Specification (Result));
1014 exit;
1016 when N_Subprogram_Body =>
1017 Result := Defining_Unit_Name (Specification (Result));
1018 exit;
1020 -- The enclosing subprogram for a pre- or postconditions should be
1021 -- the subprogram to which the pragma is attached. This is not
1022 -- always the case in the AST, as the pragma may be declared after
1023 -- the declaration of the subprogram. Return Empty in this case.
1025 when N_Pragma =>
1026 if Get_Pragma_Id (Result) = Pragma_Precondition
1027 or else
1028 Get_Pragma_Id (Result) = Pragma_Postcondition
1029 then
1030 return Empty;
1031 else
1032 Result := Parent (Result);
1033 end if;
1035 when others =>
1036 Result := Parent (Result);
1037 end case;
1038 end loop;
1040 if Nkind (Result) = N_Defining_Program_Unit_Name then
1041 Result := Defining_Identifier (Result);
1042 end if;
1044 -- Do not return a scope without a proper location
1046 if Present (Result)
1047 and then Sloc (Result) = No_Location
1048 then
1049 return Empty;
1050 end if;
1052 return Result;
1053 end Enclosing_Subprogram_Or_Package;
1055 -----------------
1056 -- Entity_Hash --
1057 -----------------
1059 function Entity_Hash (E : Entity_Id) return Entity_Hashed_Range is
1060 begin
1061 return
1062 Entity_Hashed_Range (E mod (Entity_Id (Entity_Hashed_Range'Last) + 1));
1063 end Entity_Hash;
1065 --------------------------
1066 -- Generate_Dereference --
1067 --------------------------
1069 procedure Generate_Dereference
1070 (N : Node_Id;
1071 Typ : Character := 'r')
1073 procedure Create_Heap;
1074 -- Create and decorate the special entity which denotes the heap
1076 -----------------
1077 -- Create_Heap --
1078 -----------------
1080 procedure Create_Heap is
1081 begin
1082 Name_Len := Name_Of_Heap_Variable'Length;
1083 Name_Buffer (1 .. Name_Len) := Name_Of_Heap_Variable;
1085 Heap := Make_Defining_Identifier (Standard_Location, Name_Enter);
1087 Set_Ekind (Heap, E_Variable);
1088 Set_Is_Internal (Heap, True);
1089 Set_Has_Fully_Qualified_Name (Heap);
1090 end Create_Heap;
1092 -- Local variables
1094 Loc : constant Source_Ptr := Sloc (N);
1095 Index : Nat;
1096 Ref_Scope : Entity_Id;
1098 -- Start of processing for Generate_Dereference
1100 begin
1102 if Loc > No_Location then
1103 Drefs.Increment_Last;
1104 Index := Drefs.Last;
1106 declare
1107 Deref_Entry : Xref_Entry renames Drefs.Table (Index);
1108 Deref : Xref_Key renames Deref_Entry.Key;
1110 begin
1111 if No (Heap) then
1112 Create_Heap;
1113 end if;
1115 Ref_Scope := Enclosing_Subprogram_Or_Package (N);
1117 Deref.Ent := Heap;
1118 Deref.Loc := Loc;
1119 Deref.Typ := Typ;
1121 -- It is as if the special "Heap" was defined in every scope where
1122 -- it is referenced.
1124 Deref.Eun := Get_Code_Unit (Loc);
1125 Deref.Lun := Get_Code_Unit (Loc);
1127 Deref.Ref_Scope := Ref_Scope;
1128 Deref.Ent_Scope := Ref_Scope;
1130 Deref_Entry.Def := No_Location;
1132 Deref_Entry.Ent_Scope_File := Get_Code_Unit (N);
1133 end;
1134 end if;
1135 end Generate_Dereference;
1137 ------------------------------------
1138 -- Traverse_All_Compilation_Units --
1139 ------------------------------------
1141 procedure Traverse_All_Compilation_Units (Process : Node_Processing) is
1142 begin
1143 for U in Units.First .. Last_Unit loop
1144 Traverse_Compilation_Unit (Cunit (U), Process, Inside_Stubs => False);
1145 end loop;
1146 end Traverse_All_Compilation_Units;
1148 -------------------------------
1149 -- Traverse_Compilation_Unit --
1150 -------------------------------
1152 procedure Traverse_Compilation_Unit
1153 (CU : Node_Id;
1154 Process : Node_Processing;
1155 Inside_Stubs : Boolean)
1157 Lu : Node_Id;
1159 begin
1160 -- Get Unit (checking case of subunit)
1162 Lu := Unit (CU);
1164 if Nkind (Lu) = N_Subunit then
1165 Lu := Proper_Body (Lu);
1166 end if;
1168 -- Do not add scopes for generic units
1170 if Nkind (Lu) = N_Package_Body
1171 and then Ekind (Corresponding_Spec (Lu)) in Generic_Unit_Kind
1172 then
1173 return;
1174 end if;
1176 -- Call Process on all declarations
1178 if Nkind (Lu) in N_Declaration
1179 or else Nkind (Lu) in N_Later_Decl_Item
1180 then
1181 Process (Lu);
1182 end if;
1184 -- Traverse the unit
1186 if Nkind (Lu) = N_Subprogram_Body then
1187 Traverse_Subprogram_Body (Lu, Process, Inside_Stubs);
1189 elsif Nkind (Lu) = N_Subprogram_Declaration then
1190 null;
1192 elsif Nkind (Lu) = N_Package_Declaration then
1193 Traverse_Package_Declaration (Lu, Process, Inside_Stubs);
1195 elsif Nkind (Lu) = N_Package_Body then
1196 Traverse_Package_Body (Lu, Process, Inside_Stubs);
1198 -- All other cases of compilation units (e.g. renamings), are not
1199 -- declarations, or else generic declarations which are ignored.
1201 else
1202 null;
1203 end if;
1204 end Traverse_Compilation_Unit;
1206 -----------------------------------------
1207 -- Traverse_Declarations_Or_Statements --
1208 -----------------------------------------
1210 procedure Traverse_Declarations_Or_Statements
1211 (L : List_Id;
1212 Process : Node_Processing;
1213 Inside_Stubs : Boolean)
1215 N : Node_Id;
1217 begin
1218 -- Loop through statements or declarations
1220 N := First (L);
1221 while Present (N) loop
1222 -- Call Process on all declarations
1224 if Nkind (N) in N_Declaration
1225 or else
1226 Nkind (N) in N_Later_Decl_Item
1227 then
1228 Process (N);
1229 end if;
1231 case Nkind (N) is
1233 -- Package declaration
1235 when N_Package_Declaration =>
1236 Traverse_Package_Declaration (N, Process, Inside_Stubs);
1238 -- Package body
1240 when N_Package_Body =>
1241 if Ekind (Defining_Entity (N)) /= E_Generic_Package then
1242 Traverse_Package_Body (N, Process, Inside_Stubs);
1243 end if;
1245 when N_Package_Body_Stub =>
1246 if Present (Library_Unit (N)) then
1247 declare
1248 Body_N : constant Node_Id := Get_Body_From_Stub (N);
1249 begin
1250 if Inside_Stubs
1251 and then
1252 Ekind (Defining_Entity (Body_N)) /= E_Generic_Package
1253 then
1254 Traverse_Package_Body (Body_N, Process, Inside_Stubs);
1255 end if;
1256 end;
1257 end if;
1259 -- Subprogram declaration
1261 when N_Subprogram_Declaration =>
1262 null;
1264 -- Subprogram body
1266 when N_Subprogram_Body =>
1267 if not Is_Generic_Subprogram (Defining_Entity (N)) then
1268 Traverse_Subprogram_Body (N, Process, Inside_Stubs);
1269 end if;
1271 when N_Subprogram_Body_Stub =>
1272 if Present (Library_Unit (N)) then
1273 declare
1274 Body_N : constant Node_Id := Get_Body_From_Stub (N);
1275 begin
1276 if Inside_Stubs
1277 and then
1278 not Is_Generic_Subprogram (Defining_Entity (Body_N))
1279 then
1280 Traverse_Subprogram_Body
1281 (Body_N, Process, Inside_Stubs);
1282 end if;
1283 end;
1284 end if;
1286 -- Block statement
1288 when N_Block_Statement =>
1289 Traverse_Declarations_Or_Statements
1290 (Declarations (N), Process, Inside_Stubs);
1291 Traverse_Handled_Statement_Sequence
1292 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1294 when N_If_Statement =>
1296 -- Traverse the statements in the THEN part
1298 Traverse_Declarations_Or_Statements
1299 (Then_Statements (N), Process, Inside_Stubs);
1301 -- Loop through ELSIF parts if present
1303 if Present (Elsif_Parts (N)) then
1304 declare
1305 Elif : Node_Id := First (Elsif_Parts (N));
1307 begin
1308 while Present (Elif) loop
1309 Traverse_Declarations_Or_Statements
1310 (Then_Statements (Elif), Process, Inside_Stubs);
1311 Next (Elif);
1312 end loop;
1313 end;
1314 end if;
1316 -- Finally traverse the ELSE statements if present
1318 Traverse_Declarations_Or_Statements
1319 (Else_Statements (N), Process, Inside_Stubs);
1321 -- Case statement
1323 when N_Case_Statement =>
1325 -- Process case branches
1327 declare
1328 Alt : Node_Id;
1329 begin
1330 Alt := First (Alternatives (N));
1331 while Present (Alt) loop
1332 Traverse_Declarations_Or_Statements
1333 (Statements (Alt), Process, Inside_Stubs);
1334 Next (Alt);
1335 end loop;
1336 end;
1338 -- Extended return statement
1340 when N_Extended_Return_Statement =>
1341 Traverse_Handled_Statement_Sequence
1342 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1344 -- Loop
1346 when N_Loop_Statement =>
1347 Traverse_Declarations_Or_Statements
1348 (Statements (N), Process, Inside_Stubs);
1350 -- Generic declarations are ignored
1352 when others =>
1353 null;
1354 end case;
1356 Next (N);
1357 end loop;
1358 end Traverse_Declarations_Or_Statements;
1360 -----------------------------------------
1361 -- Traverse_Handled_Statement_Sequence --
1362 -----------------------------------------
1364 procedure Traverse_Handled_Statement_Sequence
1365 (N : Node_Id;
1366 Process : Node_Processing;
1367 Inside_Stubs : Boolean)
1369 Handler : Node_Id;
1371 begin
1372 if Present (N) then
1373 Traverse_Declarations_Or_Statements
1374 (Statements (N), Process, Inside_Stubs);
1376 if Present (Exception_Handlers (N)) then
1377 Handler := First (Exception_Handlers (N));
1378 while Present (Handler) loop
1379 Traverse_Declarations_Or_Statements
1380 (Statements (Handler), Process, Inside_Stubs);
1381 Next (Handler);
1382 end loop;
1383 end if;
1384 end if;
1385 end Traverse_Handled_Statement_Sequence;
1387 ---------------------------
1388 -- Traverse_Package_Body --
1389 ---------------------------
1391 procedure Traverse_Package_Body
1392 (N : Node_Id;
1393 Process : Node_Processing;
1394 Inside_Stubs : Boolean) is
1395 begin
1396 Traverse_Declarations_Or_Statements
1397 (Declarations (N), Process, Inside_Stubs);
1398 Traverse_Handled_Statement_Sequence
1399 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1400 end Traverse_Package_Body;
1402 ----------------------------------
1403 -- Traverse_Package_Declaration --
1404 ----------------------------------
1406 procedure Traverse_Package_Declaration
1407 (N : Node_Id;
1408 Process : Node_Processing;
1409 Inside_Stubs : Boolean)
1411 Spec : constant Node_Id := Specification (N);
1412 begin
1413 Traverse_Declarations_Or_Statements
1414 (Visible_Declarations (Spec), Process, Inside_Stubs);
1415 Traverse_Declarations_Or_Statements
1416 (Private_Declarations (Spec), Process, Inside_Stubs);
1417 end Traverse_Package_Declaration;
1419 ------------------------------
1420 -- Traverse_Subprogram_Body --
1421 ------------------------------
1423 procedure Traverse_Subprogram_Body
1424 (N : Node_Id;
1425 Process : Node_Processing;
1426 Inside_Stubs : Boolean)
1428 begin
1429 Traverse_Declarations_Or_Statements
1430 (Declarations (N), Process, Inside_Stubs);
1431 Traverse_Handled_Statement_Sequence
1432 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1433 end Traverse_Subprogram_Body;
1435 end Alfa;