Daily bump.
[official-gcc.git] / gcc / ada / lib-xref-spark_specific.adb
blob0b32aada218b97f51ccb86418b0959cde2458103
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- L I B . X R E F . S P A R K _ S P E C I F I C --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2011-2013, 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 SPARK_Xrefs; use SPARK_Xrefs;
27 with Einfo; use Einfo;
28 with Nmake; use Nmake;
29 with Put_SPARK_Xrefs;
31 with GNAT.HTable;
33 separate (Lib.Xref)
34 package body SPARK_Specific is
36 ---------------------
37 -- Local Constants --
38 ---------------------
40 -- Table of SPARK_Entities, True for each entity kind used in SPARK
42 SPARK_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 SPARK
56 SPARK_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 SPARK cross-references.
84 -----------------------
85 -- Local Subprograms --
86 -----------------------
88 procedure Add_SPARK_File (Ubody, Uspec : Unit_Number_Type; Dspec : Nat);
89 -- Add file and corresponding scopes for unit to the tables
90 -- SPARK_File_Table and SPARK_Scope_Table. When two units are present for
91 -- the same compilation unit, as it happens for library-level
92 -- instantiations of generics, then Ubody /= Uspec, and all scopes are
93 -- added to the same SPARK file. Otherwise Ubody = Uspec.
95 procedure Add_SPARK_Scope (N : Node_Id);
96 -- Add scope N to the table SPARK_Scope_Table
98 procedure Add_SPARK_Xrefs;
99 -- Filter table Xrefs to add all references used in SPARK to the table
100 -- SPARK_Xref_Table.
102 procedure Detect_And_Add_SPARK_Scope (N : Node_Id);
103 -- Call Add_SPARK_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_SPARK_File --
132 --------------------
134 procedure Add_SPARK_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 := SPARK_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_SPARK_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 SPARK 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_SPARK_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 .. SPARK_Scope_Table.Last loop
181 declare
182 S : SPARK_Scope_Record renames SPARK_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 .. SPARK_Scope_Table.Last loop
199 declare
200 S : SPARK_Scope_Record renames SPARK_Scope_Table.Table (Index);
201 begin
202 if S.Scope_Num /= 0 then
203 SPARK_Scope_Table.Table (Scope_Id) := S;
204 Scope_Id := Scope_Id + 1;
205 end if;
206 end;
207 end loop;
209 SPARK_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 SPARK_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 => SPARK_Scope_Table.Last));
234 end Add_SPARK_File;
236 ---------------------
237 -- Add_SPARK_Scope --
238 ---------------------
240 procedure Add_SPARK_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 SPARK_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_SPARK_Scope;
311 ---------------------
312 -- Add_SPARK_Xrefs --
313 ---------------------
315 procedure Add_SPARK_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_SPARK_Reference
323 (E : Entity_Id;
324 Typ : Character) return Boolean;
325 -- Return whether entity reference E meets SPARK requirements. Typ is
326 -- the reference type.
328 function Is_SPARK_Scope (E : Entity_Id) return Boolean;
329 -- Return whether the entity or reference scope meets requirements for
330 -- being an SPARK scope.
332 function Is_Future_Scope_Entity
333 (E : Entity_Id;
334 S : Scope_Index) return Boolean;
335 -- Check whether entity E is in SPARK_Scope_Table at index S or higher
337 function Lt (Op1 : Natural; Op2 : Natural) return Boolean;
338 -- Comparison function for Sort call
340 procedure Move (From : Natural; To : Natural);
341 -- Move procedure for Sort call
343 procedure Update_Scope_Range
344 (S : Scope_Index;
345 From : Xref_Index;
346 To : Xref_Index);
347 -- Update the scope which maps to S with the new range From .. To
349 package Sorting is new GNAT.Heap_Sort_G (Move, Lt);
351 function Get_Scope_Num (N : Entity_Id) return Nat;
352 -- Return the scope number associated to entity N
354 procedure Set_Scope_Num (N : Entity_Id; Num : Nat);
355 -- Associate entity N to scope number Num
357 No_Scope : constant Nat := 0;
358 -- Initial scope counter
360 type Scope_Rec is record
361 Num : Nat;
362 Entity : Entity_Id;
363 end record;
364 -- Type used to relate an entity and a scope number
366 package Scopes is new GNAT.HTable.Simple_HTable
367 (Header_Num => Entity_Hashed_Range,
368 Element => Scope_Rec,
369 No_Element => (Num => No_Scope, Entity => Empty),
370 Key => Entity_Id,
371 Hash => Entity_Hash,
372 Equal => "=");
373 -- Package used to build a correspondance between entities and scope
374 -- numbers used in SPARK cross references.
376 Nrefs : Nat := Xrefs.Last;
377 -- Number of references in table. This value may get reset (reduced)
378 -- when we eliminate duplicate reference entries as well as references
379 -- not suitable for local cross-references.
381 Nrefs_Add : constant Nat := Drefs.Last;
382 -- Number of additional references which correspond to dereferences in
383 -- the source code.
385 Rnums : array (0 .. Nrefs + Nrefs_Add) of Nat;
386 -- This array contains numbers of references in the Xrefs table. This
387 -- list is sorted in output order. The extra 0'th entry is convenient
388 -- for the call to sort. When we sort the table, we move the entries in
389 -- Rnums around, but we do not move the original table entries.
391 ---------------------
392 -- Entity_Of_Scope --
393 ---------------------
395 function Entity_Of_Scope (S : Scope_Index) return Entity_Id is
396 begin
397 return SPARK_Scope_Table.Table (S).Scope_Entity;
398 end Entity_Of_Scope;
400 ---------------------
401 -- Get_Entity_Type --
402 ---------------------
404 function Get_Entity_Type (E : Entity_Id) return Character is
405 begin
406 case Ekind (E) is
407 when E_Out_Parameter => return '<';
408 when E_In_Out_Parameter => return '=';
409 when E_In_Parameter => return '>';
410 when others => return '*';
411 end case;
412 end Get_Entity_Type;
414 -------------------
415 -- Get_Scope_Num --
416 -------------------
418 function Get_Scope_Num (N : Entity_Id) return Nat is
419 begin
420 return Scopes.Get (N).Num;
421 end Get_Scope_Num;
423 ------------------------
424 -- Is_SPARK_Reference --
425 ------------------------
427 function Is_SPARK_Reference
428 (E : Entity_Id;
429 Typ : Character) return Boolean
431 begin
432 -- The only references of interest on callable entities are calls. On
433 -- non-callable entities, the only references of interest are reads
434 -- and writes.
436 if Ekind (E) in Overloadable_Kind then
437 return Typ = 's';
439 -- Objects of Task type or protected type are not SPARK references
441 elsif Present (Etype (E))
442 and then Ekind (Etype (E)) in Concurrent_Kind
443 then
444 return False;
446 -- In all other cases, result is true for reference/modify cases,
447 -- and false for all other cases.
449 else
450 return Typ = 'r' or else Typ = 'm';
451 end if;
452 end Is_SPARK_Reference;
454 --------------------
455 -- Is_SPARK_Scope --
456 --------------------
458 function Is_SPARK_Scope (E : Entity_Id) return Boolean is
459 begin
460 return Present (E)
461 and then not Is_Generic_Unit (E)
462 and then Renamed_Entity (E) = Empty
463 and then Get_Scope_Num (E) /= No_Scope;
464 end Is_SPARK_Scope;
466 ----------------------------
467 -- Is_Future_Scope_Entity --
468 ----------------------------
470 function Is_Future_Scope_Entity
471 (E : Entity_Id;
472 S : Scope_Index) return Boolean
474 function Is_Past_Scope_Entity return Boolean;
475 -- Check whether entity E is in SPARK_Scope_Table at index strictly
476 -- lower than S.
478 --------------------------
479 -- Is_Past_Scope_Entity --
480 --------------------------
482 function Is_Past_Scope_Entity return Boolean is
483 begin
484 for Index in SPARK_Scope_Table.First .. S - 1 loop
485 if SPARK_Scope_Table.Table (Index).Scope_Entity = E then
486 declare
487 Dummy : constant SPARK_Scope_Record :=
488 SPARK_Scope_Table.Table (Index);
489 pragma Unreferenced (Dummy);
490 begin
491 return True;
492 end;
493 end if;
494 end loop;
496 return False;
497 end Is_Past_Scope_Entity;
499 -- Start of processing for Is_Future_Scope_Entity
501 begin
502 for Index in S .. SPARK_Scope_Table.Last loop
503 if SPARK_Scope_Table.Table (Index).Scope_Entity = E then
504 return True;
505 end if;
506 end loop;
508 -- If this assertion fails, this means that the scope which we are
509 -- looking for has been treated already, which reveals a problem in
510 -- the order of cross-references.
512 pragma Assert (not Is_Past_Scope_Entity);
514 return False;
515 end Is_Future_Scope_Entity;
517 --------
518 -- Lt --
519 --------
521 function Lt (Op1, Op2 : Natural) return Boolean is
522 T1 : constant Xref_Entry := Xrefs.Table (Rnums (Nat (Op1)));
523 T2 : constant Xref_Entry := Xrefs.Table (Rnums (Nat (Op2)));
525 begin
526 -- First test: if entity is in different unit, sort by unit. Note:
527 -- that we use Ent_Scope_File rather than Eun, as Eun may refer to
528 -- the file where the generic scope is defined, which may differ from
529 -- the file where the enclosing scope is defined. It is the latter
530 -- which matters for a correct order here.
532 if T1.Ent_Scope_File /= T2.Ent_Scope_File then
533 return Dependency_Num (T1.Ent_Scope_File) <
534 Dependency_Num (T2.Ent_Scope_File);
536 -- Second test: within same unit, sort by location of the scope of
537 -- the entity definition.
539 elsif Get_Scope_Num (T1.Key.Ent_Scope) /=
540 Get_Scope_Num (T2.Key.Ent_Scope)
541 then
542 return Get_Scope_Num (T1.Key.Ent_Scope) <
543 Get_Scope_Num (T2.Key.Ent_Scope);
545 -- Third test: within same unit and scope, sort by location of
546 -- entity definition.
548 elsif T1.Def /= T2.Def then
549 return T1.Def < T2.Def;
551 else
552 -- Both entities must be equal at this point
554 pragma Assert (T1.Key.Ent = T2.Key.Ent);
556 -- Fourth test: if reference is in same unit as entity definition,
557 -- sort first.
559 if T1.Key.Lun /= T2.Key.Lun
560 and then T1.Ent_Scope_File = T1.Key.Lun
561 then
562 return True;
564 elsif T1.Key.Lun /= T2.Key.Lun
565 and then T2.Ent_Scope_File = T2.Key.Lun
566 then
567 return False;
569 -- Fifth test: if reference is in same unit and same scope as
570 -- entity definition, sort first.
572 elsif T1.Ent_Scope_File = T1.Key.Lun
573 and then T1.Key.Ref_Scope /= T2.Key.Ref_Scope
574 and then T1.Key.Ent_Scope = T1.Key.Ref_Scope
575 then
576 return True;
578 elsif T2.Ent_Scope_File = T2.Key.Lun
579 and then T1.Key.Ref_Scope /= T2.Key.Ref_Scope
580 and then T2.Key.Ent_Scope = T2.Key.Ref_Scope
581 then
582 return False;
584 -- Sixth test: for same entity, sort by reference location unit
586 elsif T1.Key.Lun /= T2.Key.Lun then
587 return Dependency_Num (T1.Key.Lun) <
588 Dependency_Num (T2.Key.Lun);
590 -- Seventh test: for same entity, sort by reference location scope
592 elsif Get_Scope_Num (T1.Key.Ref_Scope) /=
593 Get_Scope_Num (T2.Key.Ref_Scope)
594 then
595 return Get_Scope_Num (T1.Key.Ref_Scope) <
596 Get_Scope_Num (T2.Key.Ref_Scope);
598 -- Eighth test: order of location within referencing unit
600 elsif T1.Key.Loc /= T2.Key.Loc then
601 return T1.Key.Loc < T2.Key.Loc;
603 -- Finally, for two locations at the same address prefer the one
604 -- that does NOT have the type 'r', so that a modification or
605 -- extension takes preference, when there are more than one
606 -- reference at the same location. As a result, in the case of
607 -- entities that are in-out actuals, the read reference follows
608 -- the modify reference.
610 else
611 return T2.Key.Typ = 'r';
612 end if;
613 end if;
614 end Lt;
616 ----------
617 -- Move --
618 ----------
620 procedure Move (From : Natural; To : Natural) is
621 begin
622 Rnums (Nat (To)) := Rnums (Nat (From));
623 end Move;
625 -------------------
626 -- Set_Scope_Num --
627 -------------------
629 procedure Set_Scope_Num (N : Entity_Id; Num : Nat) is
630 begin
631 Scopes.Set (K => N, E => Scope_Rec'(Num => Num, Entity => N));
632 end Set_Scope_Num;
634 ------------------------
635 -- Update_Scope_Range --
636 ------------------------
638 procedure Update_Scope_Range
639 (S : Scope_Index;
640 From : Xref_Index;
641 To : Xref_Index)
643 begin
644 SPARK_Scope_Table.Table (S).From_Xref := From;
645 SPARK_Scope_Table.Table (S).To_Xref := To;
646 end Update_Scope_Range;
648 -- Local variables
650 Col : Nat;
651 From_Index : Xref_Index;
652 Line : Nat;
653 Loc : Source_Ptr;
654 Prev_Typ : Character;
655 Ref_Count : Nat;
656 Ref_Id : Entity_Id;
657 Ref_Name : String_Ptr;
658 Scope_Id : Scope_Index;
660 -- Start of processing for Add_SPARK_Xrefs
662 begin
663 for Index in SPARK_Scope_Table.First .. SPARK_Scope_Table.Last loop
664 declare
665 S : SPARK_Scope_Record renames SPARK_Scope_Table.Table (Index);
666 begin
667 Set_Scope_Num (S.Scope_Entity, S.Scope_Num);
668 end;
669 end loop;
671 -- Set up the pointer vector for the sort
673 for Index in 1 .. Nrefs loop
674 Rnums (Index) := Index;
675 end loop;
677 for Index in Drefs.First .. Drefs.Last loop
678 Xrefs.Append (Drefs.Table (Index));
680 Nrefs := Nrefs + 1;
681 Rnums (Nrefs) := Xrefs.Last;
682 end loop;
684 -- Capture the definition Sloc values. As in the case of normal cross
685 -- references, we have to wait until now to get the correct value.
687 for Index in 1 .. Nrefs loop
688 Xrefs.Table (Index).Def := Sloc (Xrefs.Table (Index).Key.Ent);
689 end loop;
691 -- Eliminate entries not appropriate for SPARK. Done prior to sorting
692 -- cross-references, as it discards useless references which do not have
693 -- a proper format for the comparison function (like no location).
695 Ref_Count := Nrefs;
696 Nrefs := 0;
698 for Index in 1 .. Ref_Count loop
699 declare
700 Ref : Xref_Key renames Xrefs.Table (Rnums (Index)).Key;
702 begin
703 if SPARK_Entities (Ekind (Ref.Ent))
704 and then SPARK_References (Ref.Typ)
705 and then Is_SPARK_Scope (Ref.Ent_Scope)
706 and then Is_SPARK_Scope (Ref.Ref_Scope)
707 and then Is_SPARK_Reference (Ref.Ent, Ref.Typ)
709 -- Discard references from unknown scopes, e.g. generic scopes
711 and then Get_Scope_Num (Ref.Ent_Scope) /= No_Scope
712 and then Get_Scope_Num (Ref.Ref_Scope) /= No_Scope
713 then
714 Nrefs := Nrefs + 1;
715 Rnums (Nrefs) := Rnums (Index);
716 end if;
717 end;
718 end loop;
720 -- Sort the references
722 Sorting.Sort (Integer (Nrefs));
724 -- Eliminate duplicate entries
726 -- We need this test for Ref_Count because if we force ALI file
727 -- generation in case of errors detected, it may be the case that
728 -- Nrefs is 0, so we should not reset it here.
730 if Nrefs >= 2 then
731 Ref_Count := Nrefs;
732 Nrefs := 1;
734 for Index in 2 .. Ref_Count loop
735 if Xrefs.Table (Rnums (Index)) /=
736 Xrefs.Table (Rnums (Nrefs))
737 then
738 Nrefs := Nrefs + 1;
739 Rnums (Nrefs) := Rnums (Index);
740 end if;
741 end loop;
742 end if;
744 -- Eliminate the reference if it is at the same location as the previous
745 -- one, unless it is a read-reference indicating that the entity is an
746 -- in-out actual in a call.
748 Ref_Count := Nrefs;
749 Nrefs := 0;
750 Loc := No_Location;
751 Prev_Typ := 'm';
753 for Index in 1 .. Ref_Count loop
754 declare
755 Ref : Xref_Key renames Xrefs.Table (Rnums (Index)).Key;
757 begin
758 if Ref.Loc /= Loc
759 or else (Prev_Typ = 'm' and then Ref.Typ = 'r')
760 then
761 Loc := Ref.Loc;
762 Prev_Typ := Ref.Typ;
763 Nrefs := Nrefs + 1;
764 Rnums (Nrefs) := Rnums (Index);
765 end if;
766 end;
767 end loop;
769 -- The two steps have eliminated all references, nothing to do
771 if SPARK_Scope_Table.Last = 0 then
772 return;
773 end if;
775 Ref_Id := Empty;
776 Scope_Id := 1;
777 From_Index := 1;
779 -- Loop to output references
781 for Refno in 1 .. Nrefs loop
782 declare
783 Ref_Entry : Xref_Entry renames Xrefs.Table (Rnums (Refno));
784 Ref : Xref_Key renames Ref_Entry.Key;
785 Typ : Character;
787 begin
788 -- If this assertion fails, the scope which we are looking for is
789 -- not in SPARK scope table, which reveals either a problem in the
790 -- construction of the scope table, or an erroneous scope for the
791 -- current cross-reference.
793 pragma Assert (Is_Future_Scope_Entity (Ref.Ent_Scope, Scope_Id));
795 -- Update the range of cross references to which the current scope
796 -- refers to. This may be the empty range only for the first scope
797 -- considered.
799 if Ref.Ent_Scope /= Entity_Of_Scope (Scope_Id) then
800 Update_Scope_Range
801 (S => Scope_Id,
802 From => From_Index,
803 To => SPARK_Xref_Table.Last);
805 From_Index := SPARK_Xref_Table.Last + 1;
806 end if;
808 while Ref.Ent_Scope /= Entity_Of_Scope (Scope_Id) loop
809 Scope_Id := Scope_Id + 1;
810 pragma Assert (Scope_Id <= SPARK_Scope_Table.Last);
811 end loop;
813 if Ref.Ent /= Ref_Id then
814 Ref_Name := new String'(Unique_Name (Ref.Ent));
815 end if;
817 if Ref.Ent = Heap then
818 Line := 0;
819 Col := 0;
820 else
821 Line := Int (Get_Logical_Line_Number (Ref_Entry.Def));
822 Col := Int (Get_Column_Number (Ref_Entry.Def));
823 end if;
825 -- References to constant objects are considered specially in
826 -- SPARK section, because these will be translated as constants in
827 -- the intermediate language for formal verification, and should
828 -- therefore never appear in frame conditions.
830 if Is_Constant_Object (Ref.Ent) then
831 Typ := 'c';
832 else
833 Typ := Ref.Typ;
834 end if;
836 SPARK_Xref_Table.Append (
837 (Entity_Name => Ref_Name,
838 Entity_Line => Line,
839 Etype => Get_Entity_Type (Ref.Ent),
840 Entity_Col => Col,
841 File_Num => Dependency_Num (Ref.Lun),
842 Scope_Num => Get_Scope_Num (Ref.Ref_Scope),
843 Line => Int (Get_Logical_Line_Number (Ref.Loc)),
844 Rtype => Typ,
845 Col => Int (Get_Column_Number (Ref.Loc))));
846 end;
847 end loop;
849 -- Update the range of cross references to which the scope refers to
851 Update_Scope_Range
852 (S => Scope_Id,
853 From => From_Index,
854 To => SPARK_Xref_Table.Last);
855 end Add_SPARK_Xrefs;
857 -------------------------
858 -- Collect_SPARK_Xrefs --
859 -------------------------
861 procedure Collect_SPARK_Xrefs
862 (Sdep_Table : Unit_Ref_Table;
863 Num_Sdep : Nat)
865 D1 : Nat;
866 D2 : Nat;
868 begin
869 -- Cross-references should have been computed first
871 pragma Assert (Xrefs.Last /= 0);
873 Initialize_SPARK_Tables;
875 -- Generate file and scope SPARK cross-reference information
877 D1 := 1;
878 while D1 <= Num_Sdep loop
880 -- In rare cases, when treating the library-level instantiation of a
881 -- generic, two consecutive units refer to the same compilation unit
882 -- node and entity. In that case, treat them as a single unit for the
883 -- sake of SPARK cross references by passing to Add_SPARK_File.
885 if D1 < Num_Sdep
886 and then Cunit_Entity (Sdep_Table (D1)) =
887 Cunit_Entity (Sdep_Table (D1 + 1))
888 then
889 D2 := D1 + 1;
890 else
891 D2 := D1;
892 end if;
894 Add_SPARK_File
895 (Ubody => Sdep_Table (D1),
896 Uspec => Sdep_Table (D2),
897 Dspec => D2);
898 D1 := D2 + 1;
899 end loop;
901 -- Fill in the spec information when relevant
903 declare
904 package Entity_Hash_Table is new
905 GNAT.HTable.Simple_HTable
906 (Header_Num => Entity_Hashed_Range,
907 Element => Scope_Index,
908 No_Element => 0,
909 Key => Entity_Id,
910 Hash => Entity_Hash,
911 Equal => "=");
913 begin
914 -- Fill in the hash-table
916 for S in SPARK_Scope_Table.First .. SPARK_Scope_Table.Last loop
917 declare
918 Srec : SPARK_Scope_Record renames SPARK_Scope_Table.Table (S);
919 begin
920 Entity_Hash_Table.Set (Srec.Scope_Entity, S);
921 end;
922 end loop;
924 -- Use the hash-table to locate spec entities
926 for S in SPARK_Scope_Table.First .. SPARK_Scope_Table.Last loop
927 declare
928 Srec : SPARK_Scope_Record renames SPARK_Scope_Table.Table (S);
930 Spec_Entity : constant Entity_Id :=
931 Unique_Entity (Srec.Scope_Entity);
932 Spec_Scope : constant Scope_Index :=
933 Entity_Hash_Table.Get (Spec_Entity);
935 begin
936 -- Generic spec may be missing in which case Spec_Scope is zero
938 if Spec_Entity /= Srec.Scope_Entity
939 and then Spec_Scope /= 0
940 then
941 Srec.Spec_File_Num :=
942 SPARK_Scope_Table.Table (Spec_Scope).File_Num;
943 Srec.Spec_Scope_Num :=
944 SPARK_Scope_Table.Table (Spec_Scope).Scope_Num;
945 end if;
946 end;
947 end loop;
948 end;
950 -- Generate SPARK cross-reference information
952 Add_SPARK_Xrefs;
953 end Collect_SPARK_Xrefs;
955 --------------------------------
956 -- Detect_And_Add_SPARK_Scope --
957 --------------------------------
959 procedure Detect_And_Add_SPARK_Scope (N : Node_Id) is
960 begin
961 if Nkind_In (N, N_Subprogram_Declaration,
962 N_Subprogram_Body,
963 N_Subprogram_Body_Stub,
964 N_Package_Declaration,
965 N_Package_Body)
966 then
967 Add_SPARK_Scope (N);
968 end if;
969 end Detect_And_Add_SPARK_Scope;
971 -------------------------------------
972 -- Enclosing_Subprogram_Or_Package --
973 -------------------------------------
975 function Enclosing_Subprogram_Or_Package (N : Node_Id) return Entity_Id is
976 Result : Entity_Id;
978 begin
979 -- If N is the defining identifier for a subprogram, then return the
980 -- enclosing subprogram or package, not this subprogram.
982 if Nkind_In (N, N_Defining_Identifier, N_Defining_Operator_Symbol)
983 and then Nkind (Parent (N)) in N_Subprogram_Specification
984 then
985 Result := Parent (Parent (Parent (N)));
986 else
987 Result := N;
988 end if;
990 while Present (Result) loop
991 case Nkind (Result) is
992 when N_Package_Specification =>
993 Result := Defining_Unit_Name (Result);
994 exit;
996 when N_Package_Body =>
997 Result := Defining_Unit_Name (Result);
998 exit;
1000 when N_Subprogram_Specification =>
1001 Result := Defining_Unit_Name (Result);
1002 exit;
1004 when N_Subprogram_Declaration =>
1005 Result := Defining_Unit_Name (Specification (Result));
1006 exit;
1008 when N_Subprogram_Body =>
1009 Result := Defining_Unit_Name (Specification (Result));
1010 exit;
1012 when N_Pragma =>
1014 -- The enclosing subprogram for a precondition, postcondition,
1015 -- or contract case should be the declaration preceding the
1016 -- pragma (skipping any other pragmas between this pragma and
1017 -- this declaration.
1019 while Nkind (Result) = N_Pragma
1020 and then Is_List_Member (Result)
1021 and then Present (Prev (Result))
1022 loop
1023 Result := Prev (Result);
1024 end loop;
1026 if Nkind (Result) = N_Pragma then
1027 Result := Parent (Result);
1028 end if;
1030 when others =>
1031 Result := Parent (Result);
1032 end case;
1033 end loop;
1035 if Nkind (Result) = N_Defining_Program_Unit_Name then
1036 Result := Defining_Identifier (Result);
1037 end if;
1039 -- Do not return a scope without a proper location
1041 if Present (Result)
1042 and then Sloc (Result) = No_Location
1043 then
1044 return Empty;
1045 end if;
1047 return Result;
1048 end Enclosing_Subprogram_Or_Package;
1050 -----------------
1051 -- Entity_Hash --
1052 -----------------
1054 function Entity_Hash (E : Entity_Id) return Entity_Hashed_Range is
1055 begin
1056 return
1057 Entity_Hashed_Range (E mod (Entity_Id (Entity_Hashed_Range'Last) + 1));
1058 end Entity_Hash;
1060 --------------------------
1061 -- Generate_Dereference --
1062 --------------------------
1064 procedure Generate_Dereference
1065 (N : Node_Id;
1066 Typ : Character := 'r')
1068 procedure Create_Heap;
1069 -- Create and decorate the special entity which denotes the heap
1071 -----------------
1072 -- Create_Heap --
1073 -----------------
1075 procedure Create_Heap is
1076 begin
1077 Name_Len := Name_Of_Heap_Variable'Length;
1078 Name_Buffer (1 .. Name_Len) := Name_Of_Heap_Variable;
1080 Heap := Make_Defining_Identifier (Standard_Location, Name_Enter);
1082 Set_Ekind (Heap, E_Variable);
1083 Set_Is_Internal (Heap, True);
1084 Set_Has_Fully_Qualified_Name (Heap);
1085 end Create_Heap;
1087 -- Local variables
1089 Loc : constant Source_Ptr := Sloc (N);
1090 Index : Nat;
1091 Ref_Scope : Entity_Id;
1093 -- Start of processing for Generate_Dereference
1095 begin
1097 if Loc > No_Location then
1098 Drefs.Increment_Last;
1099 Index := Drefs.Last;
1101 declare
1102 Deref_Entry : Xref_Entry renames Drefs.Table (Index);
1103 Deref : Xref_Key renames Deref_Entry.Key;
1105 begin
1106 if No (Heap) then
1107 Create_Heap;
1108 end if;
1110 Ref_Scope := Enclosing_Subprogram_Or_Package (N);
1112 Deref.Ent := Heap;
1113 Deref.Loc := Loc;
1114 Deref.Typ := Typ;
1116 -- It is as if the special "Heap" was defined in every scope where
1117 -- it is referenced.
1119 Deref.Eun := Get_Code_Unit (Loc);
1120 Deref.Lun := Get_Code_Unit (Loc);
1122 Deref.Ref_Scope := Ref_Scope;
1123 Deref.Ent_Scope := Ref_Scope;
1125 Deref_Entry.Def := No_Location;
1127 Deref_Entry.Ent_Scope_File := Get_Code_Unit (N);
1128 end;
1129 end if;
1130 end Generate_Dereference;
1132 ------------------------------------
1133 -- Traverse_All_Compilation_Units --
1134 ------------------------------------
1136 procedure Traverse_All_Compilation_Units (Process : Node_Processing) is
1137 begin
1138 for U in Units.First .. Last_Unit loop
1139 Traverse_Compilation_Unit (Cunit (U), Process, Inside_Stubs => False);
1140 end loop;
1141 end Traverse_All_Compilation_Units;
1143 -------------------------------
1144 -- Traverse_Compilation_Unit --
1145 -------------------------------
1147 procedure Traverse_Compilation_Unit
1148 (CU : Node_Id;
1149 Process : Node_Processing;
1150 Inside_Stubs : Boolean)
1152 Lu : Node_Id;
1154 begin
1155 -- Get Unit (checking case of subunit)
1157 Lu := Unit (CU);
1159 if Nkind (Lu) = N_Subunit then
1160 Lu := Proper_Body (Lu);
1161 end if;
1163 -- Do not add scopes for generic units
1165 if Nkind (Lu) = N_Package_Body
1166 and then Ekind (Corresponding_Spec (Lu)) in Generic_Unit_Kind
1167 then
1168 return;
1169 end if;
1171 -- Call Process on all declarations
1173 if Nkind (Lu) in N_Declaration
1174 or else Nkind (Lu) in N_Later_Decl_Item
1175 then
1176 Process (Lu);
1177 end if;
1179 -- Traverse the unit
1181 if Nkind (Lu) = N_Subprogram_Body then
1182 Traverse_Subprogram_Body (Lu, Process, Inside_Stubs);
1184 elsif Nkind (Lu) = N_Subprogram_Declaration then
1185 null;
1187 elsif Nkind (Lu) = N_Package_Declaration then
1188 Traverse_Package_Declaration (Lu, Process, Inside_Stubs);
1190 elsif Nkind (Lu) = N_Package_Body then
1191 Traverse_Package_Body (Lu, Process, Inside_Stubs);
1193 -- All other cases of compilation units (e.g. renamings), are not
1194 -- declarations, or else generic declarations which are ignored.
1196 else
1197 null;
1198 end if;
1199 end Traverse_Compilation_Unit;
1201 -----------------------------------------
1202 -- Traverse_Declarations_Or_Statements --
1203 -----------------------------------------
1205 procedure Traverse_Declarations_Or_Statements
1206 (L : List_Id;
1207 Process : Node_Processing;
1208 Inside_Stubs : Boolean)
1210 N : Node_Id;
1212 begin
1213 -- Loop through statements or declarations
1215 N := First (L);
1216 while Present (N) loop
1217 -- Call Process on all declarations
1219 if Nkind (N) in N_Declaration
1220 or else
1221 Nkind (N) in N_Later_Decl_Item
1222 then
1223 Process (N);
1224 end if;
1226 case Nkind (N) is
1228 -- Package declaration
1230 when N_Package_Declaration =>
1231 Traverse_Package_Declaration (N, Process, Inside_Stubs);
1233 -- Package body
1235 when N_Package_Body =>
1236 if Ekind (Defining_Entity (N)) /= E_Generic_Package then
1237 Traverse_Package_Body (N, Process, Inside_Stubs);
1238 end if;
1240 when N_Package_Body_Stub =>
1241 if Present (Library_Unit (N)) then
1242 declare
1243 Body_N : constant Node_Id := Get_Body_From_Stub (N);
1244 begin
1245 if Inside_Stubs
1246 and then
1247 Ekind (Defining_Entity (Body_N)) /= E_Generic_Package
1248 then
1249 Traverse_Package_Body (Body_N, Process, Inside_Stubs);
1250 end if;
1251 end;
1252 end if;
1254 -- Subprogram declaration
1256 when N_Subprogram_Declaration =>
1257 null;
1259 -- Subprogram body
1261 when N_Subprogram_Body =>
1262 if not Is_Generic_Subprogram (Defining_Entity (N)) then
1263 Traverse_Subprogram_Body (N, Process, Inside_Stubs);
1264 end if;
1266 when N_Subprogram_Body_Stub =>
1267 if Present (Library_Unit (N)) then
1268 declare
1269 Body_N : constant Node_Id := Get_Body_From_Stub (N);
1270 begin
1271 if Inside_Stubs
1272 and then
1273 not Is_Generic_Subprogram (Defining_Entity (Body_N))
1274 then
1275 Traverse_Subprogram_Body
1276 (Body_N, Process, Inside_Stubs);
1277 end if;
1278 end;
1279 end if;
1281 -- Block statement
1283 when N_Block_Statement =>
1284 Traverse_Declarations_Or_Statements
1285 (Declarations (N), Process, Inside_Stubs);
1286 Traverse_Handled_Statement_Sequence
1287 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1289 when N_If_Statement =>
1291 -- Traverse the statements in the THEN part
1293 Traverse_Declarations_Or_Statements
1294 (Then_Statements (N), Process, Inside_Stubs);
1296 -- Loop through ELSIF parts if present
1298 if Present (Elsif_Parts (N)) then
1299 declare
1300 Elif : Node_Id := First (Elsif_Parts (N));
1302 begin
1303 while Present (Elif) loop
1304 Traverse_Declarations_Or_Statements
1305 (Then_Statements (Elif), Process, Inside_Stubs);
1306 Next (Elif);
1307 end loop;
1308 end;
1309 end if;
1311 -- Finally traverse the ELSE statements if present
1313 Traverse_Declarations_Or_Statements
1314 (Else_Statements (N), Process, Inside_Stubs);
1316 -- Case statement
1318 when N_Case_Statement =>
1320 -- Process case branches
1322 declare
1323 Alt : Node_Id;
1324 begin
1325 Alt := First (Alternatives (N));
1326 while Present (Alt) loop
1327 Traverse_Declarations_Or_Statements
1328 (Statements (Alt), Process, Inside_Stubs);
1329 Next (Alt);
1330 end loop;
1331 end;
1333 -- Extended return statement
1335 when N_Extended_Return_Statement =>
1336 Traverse_Handled_Statement_Sequence
1337 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1339 -- Loop
1341 when N_Loop_Statement =>
1342 Traverse_Declarations_Or_Statements
1343 (Statements (N), Process, Inside_Stubs);
1345 -- Generic declarations are ignored
1347 when others =>
1348 null;
1349 end case;
1351 Next (N);
1352 end loop;
1353 end Traverse_Declarations_Or_Statements;
1355 -----------------------------------------
1356 -- Traverse_Handled_Statement_Sequence --
1357 -----------------------------------------
1359 procedure Traverse_Handled_Statement_Sequence
1360 (N : Node_Id;
1361 Process : Node_Processing;
1362 Inside_Stubs : Boolean)
1364 Handler : Node_Id;
1366 begin
1367 if Present (N) then
1368 Traverse_Declarations_Or_Statements
1369 (Statements (N), Process, Inside_Stubs);
1371 if Present (Exception_Handlers (N)) then
1372 Handler := First (Exception_Handlers (N));
1373 while Present (Handler) loop
1374 Traverse_Declarations_Or_Statements
1375 (Statements (Handler), Process, Inside_Stubs);
1376 Next (Handler);
1377 end loop;
1378 end if;
1379 end if;
1380 end Traverse_Handled_Statement_Sequence;
1382 ---------------------------
1383 -- Traverse_Package_Body --
1384 ---------------------------
1386 procedure Traverse_Package_Body
1387 (N : Node_Id;
1388 Process : Node_Processing;
1389 Inside_Stubs : Boolean) is
1390 begin
1391 Traverse_Declarations_Or_Statements
1392 (Declarations (N), Process, Inside_Stubs);
1393 Traverse_Handled_Statement_Sequence
1394 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1395 end Traverse_Package_Body;
1397 ----------------------------------
1398 -- Traverse_Package_Declaration --
1399 ----------------------------------
1401 procedure Traverse_Package_Declaration
1402 (N : Node_Id;
1403 Process : Node_Processing;
1404 Inside_Stubs : Boolean)
1406 Spec : constant Node_Id := Specification (N);
1407 begin
1408 Traverse_Declarations_Or_Statements
1409 (Visible_Declarations (Spec), Process, Inside_Stubs);
1410 Traverse_Declarations_Or_Statements
1411 (Private_Declarations (Spec), Process, Inside_Stubs);
1412 end Traverse_Package_Declaration;
1414 ------------------------------
1415 -- Traverse_Subprogram_Body --
1416 ------------------------------
1418 procedure Traverse_Subprogram_Body
1419 (N : Node_Id;
1420 Process : Node_Processing;
1421 Inside_Stubs : Boolean)
1423 begin
1424 Traverse_Declarations_Or_Statements
1425 (Declarations (N), Process, Inside_Stubs);
1426 Traverse_Handled_Statement_Sequence
1427 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1428 end Traverse_Subprogram_Body;
1430 end SPARK_Specific;