2015-09-28 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / ada / lib-xref-spark_specific.adb
blobb38d65b23dd4894a75161c16c276413bde236940
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-2014, 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 Einfo; use Einfo;
27 with Nmake; use Nmake;
28 with SPARK_Xrefs; use SPARK_Xrefs;
30 with GNAT.HTable;
32 separate (Lib.Xref)
33 package body SPARK_Specific is
35 ---------------------
36 -- Local Constants --
37 ---------------------
39 -- Table of SPARK_Entities, True for each entity kind used in SPARK
41 SPARK_Entities : constant array (Entity_Kind) of Boolean :=
42 (E_Constant => True,
43 E_Function => True,
44 E_In_Out_Parameter => True,
45 E_In_Parameter => True,
46 E_Loop_Parameter => True,
47 E_Operator => True,
48 E_Out_Parameter => True,
49 E_Procedure => True,
50 E_Variable => True,
51 others => False);
53 -- True for each reference type used in SPARK
55 SPARK_References : constant array (Character) of Boolean :=
56 ('m' => True,
57 'r' => True,
58 's' => True,
59 others => False);
61 type Entity_Hashed_Range is range 0 .. 255;
62 -- Size of hash table headers
64 ---------------------
65 -- Local Variables --
66 ---------------------
68 Heap : Entity_Id := Empty;
69 -- A special entity which denotes the heap object
71 package Drefs is new Table.Table (
72 Table_Component_Type => Xref_Entry,
73 Table_Index_Type => Xref_Entry_Number,
74 Table_Low_Bound => 1,
75 Table_Initial => Alloc.Drefs_Initial,
76 Table_Increment => Alloc.Drefs_Increment,
77 Table_Name => "Drefs");
78 -- Table of cross-references for reads and writes through explicit
79 -- dereferences, that are output as reads/writes to the special variable
80 -- "Heap". These references are added to the regular references when
81 -- computing SPARK cross-references.
83 -----------------------
84 -- Local Subprograms --
85 -----------------------
87 procedure Add_SPARK_File (Ubody, Uspec : Unit_Number_Type; Dspec : Nat);
88 -- Add file and corresponding scopes for unit to the tables
89 -- SPARK_File_Table and SPARK_Scope_Table. When two units are present for
90 -- the same compilation unit, as it happens for library-level
91 -- instantiations of generics, then Ubody /= Uspec, and all scopes are
92 -- added to the same SPARK file. Otherwise Ubody = Uspec.
94 procedure Add_SPARK_Scope (N : Node_Id);
95 -- Add scope N to the table SPARK_Scope_Table
97 procedure Add_SPARK_Xrefs;
98 -- Filter table Xrefs to add all references used in SPARK to the table
99 -- SPARK_Xref_Table.
101 procedure Detect_And_Add_SPARK_Scope (N : Node_Id);
102 -- Call Add_SPARK_Scope on scopes
104 function Entity_Hash (E : Entity_Id) return Entity_Hashed_Range;
105 -- Hash function for hash table
107 procedure Traverse_Declarations_Or_Statements
108 (L : List_Id;
109 Process : Node_Processing;
110 Inside_Stubs : Boolean);
111 procedure Traverse_Handled_Statement_Sequence
112 (N : Node_Id;
113 Process : Node_Processing;
114 Inside_Stubs : Boolean);
115 procedure Traverse_Package_Body
116 (N : Node_Id;
117 Process : Node_Processing;
118 Inside_Stubs : Boolean);
119 procedure Traverse_Package_Declaration
120 (N : Node_Id;
121 Process : Node_Processing;
122 Inside_Stubs : Boolean);
123 procedure Traverse_Subprogram_Body
124 (N : Node_Id;
125 Process : Node_Processing;
126 Inside_Stubs : Boolean);
127 -- Traverse corresponding construct, calling Process on all declarations
129 --------------------
130 -- Add_SPARK_File --
131 --------------------
133 procedure Add_SPARK_File (Ubody, Uspec : Unit_Number_Type; Dspec : Nat) is
134 File : constant Source_File_Index := Source_Index (Uspec);
135 From : Scope_Index;
137 File_Name : String_Ptr;
138 Unit_File_Name : String_Ptr;
140 begin
141 -- Source file could be inexistant as a result of an error, if option
142 -- gnatQ is used.
144 if File = No_Source_File then
145 return;
146 end if;
148 From := SPARK_Scope_Table.Last + 1;
150 -- Unit might not have an associated compilation unit, as seen in code
151 -- filling Sdep_Table in Write_ALI.
153 if Present (Cunit (Ubody)) then
154 Traverse_Compilation_Unit
155 (CU => Cunit (Ubody),
156 Process => Detect_And_Add_SPARK_Scope'Access,
157 Inside_Stubs => False);
158 end if;
160 -- When two units are present for the same compilation unit, as it
161 -- happens for library-level instantiations of generics, then add all
162 -- scopes to the same SPARK file.
164 if Ubody /= Uspec then
165 if Present (Cunit (Uspec)) then
166 Traverse_Compilation_Unit
167 (CU => Cunit (Uspec),
168 Process => Detect_And_Add_SPARK_Scope'Access,
169 Inside_Stubs => False);
170 end if;
171 end if;
173 -- Update scope numbers
175 declare
176 Scope_Id : Int;
177 begin
178 Scope_Id := 1;
179 for Index in From .. SPARK_Scope_Table.Last loop
180 declare
181 S : SPARK_Scope_Record renames SPARK_Scope_Table.Table (Index);
182 begin
183 S.Scope_Num := Scope_Id;
184 S.File_Num := Dspec;
185 Scope_Id := Scope_Id + 1;
186 end;
187 end loop;
188 end;
190 -- Remove those scopes previously marked for removal
192 declare
193 Scope_Id : Scope_Index;
195 begin
196 Scope_Id := From;
197 for Index in From .. SPARK_Scope_Table.Last loop
198 declare
199 S : SPARK_Scope_Record renames SPARK_Scope_Table.Table (Index);
200 begin
201 if S.Scope_Num /= 0 then
202 SPARK_Scope_Table.Table (Scope_Id) := S;
203 Scope_Id := Scope_Id + 1;
204 end if;
205 end;
206 end loop;
208 SPARK_Scope_Table.Set_Last (Scope_Id - 1);
209 end;
211 -- Make entry for new file in file table
213 Get_Name_String (Reference_Name (File));
214 File_Name := new String'(Name_Buffer (1 .. Name_Len));
216 -- For subunits, also retrieve the file name of the unit. Only do so if
217 -- unit has an associated compilation unit.
219 if Present (Cunit (Uspec))
220 and then Present (Cunit (Unit (File)))
221 and then Nkind (Unit (Cunit (Unit (File)))) = N_Subunit
222 then
223 Get_Name_String (Reference_Name (Main_Source_File));
224 Unit_File_Name := new String'(Name_Buffer (1 .. Name_Len));
225 end if;
227 SPARK_File_Table.Append (
228 (File_Name => File_Name,
229 Unit_File_Name => Unit_File_Name,
230 File_Num => Dspec,
231 From_Scope => From,
232 To_Scope => SPARK_Scope_Table.Last));
233 end Add_SPARK_File;
235 ---------------------
236 -- Add_SPARK_Scope --
237 ---------------------
239 procedure Add_SPARK_Scope (N : Node_Id) is
240 E : constant Entity_Id := Defining_Entity (N);
241 Loc : constant Source_Ptr := Sloc (E);
242 Typ : Character;
244 begin
245 -- Ignore scopes without a proper location
247 if Sloc (N) = No_Location then
248 return;
249 end if;
251 case Ekind (E) is
252 when E_Function | E_Generic_Function =>
253 Typ := 'V';
255 when E_Procedure | E_Generic_Procedure =>
256 Typ := 'U';
258 when E_Subprogram_Body =>
259 declare
260 Spec : Node_Id;
262 begin
263 Spec := Parent (E);
265 if Nkind (Spec) = N_Defining_Program_Unit_Name then
266 Spec := Parent (Spec);
267 end if;
269 if Nkind (Spec) = N_Function_Specification then
270 Typ := 'V';
271 else
272 pragma Assert
273 (Nkind (Spec) = N_Procedure_Specification);
274 Typ := 'U';
275 end if;
276 end;
278 when E_Package | E_Package_Body | E_Generic_Package =>
279 Typ := 'K';
281 when E_Void =>
282 -- Compilation of prj-attr.adb with -gnatn creates a node with
283 -- entity E_Void for the package defined at a-charac.ads16:13
285 -- ??? TBD
287 return;
289 when others =>
290 raise Program_Error;
291 end case;
293 -- File_Num and Scope_Num are filled later. From_Xref and To_Xref are
294 -- filled even later, but are initialized to represent an empty range.
296 SPARK_Scope_Table.Append (
297 (Scope_Name => new String'(Unique_Name (E)),
298 File_Num => 0,
299 Scope_Num => 0,
300 Spec_File_Num => 0,
301 Spec_Scope_Num => 0,
302 Line => Nat (Get_Logical_Line_Number (Loc)),
303 Stype => Typ,
304 Col => Nat (Get_Column_Number (Loc)),
305 From_Xref => 1,
306 To_Xref => 0,
307 Scope_Entity => E));
308 end Add_SPARK_Scope;
310 ---------------------
311 -- Add_SPARK_Xrefs --
312 ---------------------
314 procedure Add_SPARK_Xrefs is
315 function Entity_Of_Scope (S : Scope_Index) return Entity_Id;
316 -- Return the entity which maps to the input scope index
318 function Get_Entity_Type (E : Entity_Id) return Character;
319 -- Return a character representing the type of entity
321 function Is_SPARK_Reference
322 (E : Entity_Id;
323 Typ : Character) return Boolean;
324 -- Return whether entity reference E meets SPARK requirements. Typ is
325 -- the reference type.
327 function Is_SPARK_Scope (E : Entity_Id) return Boolean;
328 -- Return whether the entity or reference scope meets requirements for
329 -- being an SPARK scope.
331 function Is_Future_Scope_Entity
332 (E : Entity_Id;
333 S : Scope_Index) return Boolean;
334 -- Check whether entity E is in SPARK_Scope_Table at index S or higher
336 function Lt (Op1 : Natural; Op2 : Natural) return Boolean;
337 -- Comparison function for Sort call
339 procedure Move (From : Natural; To : Natural);
340 -- Move procedure for Sort call
342 procedure Update_Scope_Range
343 (S : Scope_Index;
344 From : Xref_Index;
345 To : Xref_Index);
346 -- Update the scope which maps to S with the new range From .. To
348 package Sorting is new GNAT.Heap_Sort_G (Move, Lt);
350 function Get_Scope_Num (N : Entity_Id) return Nat;
351 -- Return the scope number associated to entity N
353 procedure Set_Scope_Num (N : Entity_Id; Num : Nat);
354 -- Associate entity N to scope number Num
356 No_Scope : constant Nat := 0;
357 -- Initial scope counter
359 type Scope_Rec is record
360 Num : Nat;
361 Entity : Entity_Id;
362 end record;
363 -- Type used to relate an entity and a scope number
365 package Scopes is new GNAT.HTable.Simple_HTable
366 (Header_Num => Entity_Hashed_Range,
367 Element => Scope_Rec,
368 No_Element => (Num => No_Scope, Entity => Empty),
369 Key => Entity_Id,
370 Hash => Entity_Hash,
371 Equal => "=");
372 -- Package used to build a correspondance between entities and scope
373 -- numbers used in SPARK cross references.
375 Nrefs : Nat := Xrefs.Last;
376 -- Number of references in table. This value may get reset (reduced)
377 -- when we eliminate duplicate reference entries as well as references
378 -- not suitable for local cross-references.
380 Nrefs_Add : constant Nat := Drefs.Last;
381 -- Number of additional references which correspond to dereferences in
382 -- the source code.
384 Rnums : array (0 .. Nrefs + Nrefs_Add) of Nat;
385 -- This array contains numbers of references in the Xrefs table. This
386 -- list is sorted in output order. The extra 0'th entry is convenient
387 -- for the call to sort. When we sort the table, we move the entries in
388 -- Rnums around, but we do not move the original table entries.
390 ---------------------
391 -- Entity_Of_Scope --
392 ---------------------
394 function Entity_Of_Scope (S : Scope_Index) return Entity_Id is
395 begin
396 return SPARK_Scope_Table.Table (S).Scope_Entity;
397 end Entity_Of_Scope;
399 ---------------------
400 -- Get_Entity_Type --
401 ---------------------
403 function Get_Entity_Type (E : Entity_Id) return Character is
404 begin
405 case Ekind (E) is
406 when E_Out_Parameter => return '<';
407 when E_In_Out_Parameter => return '=';
408 when E_In_Parameter => return '>';
409 when others => return '*';
410 end case;
411 end Get_Entity_Type;
413 -------------------
414 -- Get_Scope_Num --
415 -------------------
417 function Get_Scope_Num (N : Entity_Id) return Nat is
418 begin
419 return Scopes.Get (N).Num;
420 end Get_Scope_Num;
422 ------------------------
423 -- Is_SPARK_Reference --
424 ------------------------
426 function Is_SPARK_Reference
427 (E : Entity_Id;
428 Typ : Character) return Boolean
430 begin
431 -- The only references of interest on callable entities are calls. On
432 -- non-callable entities, the only references of interest are reads
433 -- and writes.
435 if Ekind (E) in Overloadable_Kind then
436 return Typ = 's';
438 -- Objects of Task type or protected type are not SPARK references
440 elsif Present (Etype (E))
441 and then Ekind (Etype (E)) in Concurrent_Kind
442 then
443 return False;
445 -- In all other cases, result is true for reference/modify cases,
446 -- and false for all other cases.
448 else
449 return Typ = 'r' or else Typ = 'm';
450 end if;
451 end Is_SPARK_Reference;
453 --------------------
454 -- Is_SPARK_Scope --
455 --------------------
457 function Is_SPARK_Scope (E : Entity_Id) return Boolean is
458 begin
459 return Present (E)
460 and then not Is_Generic_Unit (E)
461 and then Renamed_Entity (E) = Empty
462 and then Get_Scope_Num (E) /= No_Scope;
463 end Is_SPARK_Scope;
465 ----------------------------
466 -- Is_Future_Scope_Entity --
467 ----------------------------
469 function Is_Future_Scope_Entity
470 (E : Entity_Id;
471 S : Scope_Index) return Boolean
473 function Is_Past_Scope_Entity return Boolean;
474 -- Check whether entity E is in SPARK_Scope_Table at index strictly
475 -- lower than S.
477 --------------------------
478 -- Is_Past_Scope_Entity --
479 --------------------------
481 function Is_Past_Scope_Entity return Boolean is
482 begin
483 for Index in SPARK_Scope_Table.First .. S - 1 loop
484 if SPARK_Scope_Table.Table (Index).Scope_Entity = E then
485 declare
486 Dummy : constant SPARK_Scope_Record :=
487 SPARK_Scope_Table.Table (Index);
488 begin
489 return True;
490 end;
491 end if;
492 end loop;
494 return False;
495 end Is_Past_Scope_Entity;
497 -- Start of processing for Is_Future_Scope_Entity
499 begin
500 for Index in S .. SPARK_Scope_Table.Last loop
501 if SPARK_Scope_Table.Table (Index).Scope_Entity = E then
502 return True;
503 end if;
504 end loop;
506 -- If this assertion fails, this means that the scope which we are
507 -- looking for has been treated already, which reveals a problem in
508 -- the order of cross-references.
510 pragma Assert (not Is_Past_Scope_Entity);
512 return False;
513 end Is_Future_Scope_Entity;
515 --------
516 -- Lt --
517 --------
519 function Lt (Op1, Op2 : Natural) return Boolean is
520 T1 : constant Xref_Entry := Xrefs.Table (Rnums (Nat (Op1)));
521 T2 : constant Xref_Entry := Xrefs.Table (Rnums (Nat (Op2)));
523 begin
524 -- First test: if entity is in different unit, sort by unit. Note:
525 -- that we use Ent_Scope_File rather than Eun, as Eun may refer to
526 -- the file where the generic scope is defined, which may differ from
527 -- the file where the enclosing scope is defined. It is the latter
528 -- which matters for a correct order here.
530 if T1.Ent_Scope_File /= T2.Ent_Scope_File then
531 return Dependency_Num (T1.Ent_Scope_File) <
532 Dependency_Num (T2.Ent_Scope_File);
534 -- Second test: within same unit, sort by location of the scope of
535 -- the entity definition.
537 elsif Get_Scope_Num (T1.Key.Ent_Scope) /=
538 Get_Scope_Num (T2.Key.Ent_Scope)
539 then
540 return Get_Scope_Num (T1.Key.Ent_Scope) <
541 Get_Scope_Num (T2.Key.Ent_Scope);
543 -- Third test: within same unit and scope, sort by location of
544 -- entity definition.
546 elsif T1.Def /= T2.Def then
547 return T1.Def < T2.Def;
549 else
550 -- Both entities must be equal at this point
552 pragma Assert (T1.Key.Ent = T2.Key.Ent);
554 -- Fourth test: if reference is in same unit as entity definition,
555 -- sort first.
557 if T1.Key.Lun /= T2.Key.Lun
558 and then T1.Ent_Scope_File = T1.Key.Lun
559 then
560 return True;
562 elsif T1.Key.Lun /= T2.Key.Lun
563 and then T2.Ent_Scope_File = T2.Key.Lun
564 then
565 return False;
567 -- Fifth test: if reference is in same unit and same scope as
568 -- entity definition, sort first.
570 elsif T1.Ent_Scope_File = T1.Key.Lun
571 and then T1.Key.Ref_Scope /= T2.Key.Ref_Scope
572 and then T1.Key.Ent_Scope = T1.Key.Ref_Scope
573 then
574 return True;
576 elsif T2.Ent_Scope_File = T2.Key.Lun
577 and then T1.Key.Ref_Scope /= T2.Key.Ref_Scope
578 and then T2.Key.Ent_Scope = T2.Key.Ref_Scope
579 then
580 return False;
582 -- Sixth test: for same entity, sort by reference location unit
584 elsif T1.Key.Lun /= T2.Key.Lun then
585 return Dependency_Num (T1.Key.Lun) <
586 Dependency_Num (T2.Key.Lun);
588 -- Seventh test: for same entity, sort by reference location scope
590 elsif Get_Scope_Num (T1.Key.Ref_Scope) /=
591 Get_Scope_Num (T2.Key.Ref_Scope)
592 then
593 return Get_Scope_Num (T1.Key.Ref_Scope) <
594 Get_Scope_Num (T2.Key.Ref_Scope);
596 -- Eighth test: order of location within referencing unit
598 elsif T1.Key.Loc /= T2.Key.Loc then
599 return T1.Key.Loc < T2.Key.Loc;
601 -- Finally, for two locations at the same address prefer the one
602 -- that does NOT have the type 'r', so that a modification or
603 -- extension takes preference, when there are more than one
604 -- reference at the same location. As a result, in the case of
605 -- entities that are in-out actuals, the read reference follows
606 -- the modify reference.
608 else
609 return T2.Key.Typ = 'r';
610 end if;
611 end if;
612 end Lt;
614 ----------
615 -- Move --
616 ----------
618 procedure Move (From : Natural; To : Natural) is
619 begin
620 Rnums (Nat (To)) := Rnums (Nat (From));
621 end Move;
623 -------------------
624 -- Set_Scope_Num --
625 -------------------
627 procedure Set_Scope_Num (N : Entity_Id; Num : Nat) is
628 begin
629 Scopes.Set (K => N, E => Scope_Rec'(Num => Num, Entity => N));
630 end Set_Scope_Num;
632 ------------------------
633 -- Update_Scope_Range --
634 ------------------------
636 procedure Update_Scope_Range
637 (S : Scope_Index;
638 From : Xref_Index;
639 To : Xref_Index)
641 begin
642 SPARK_Scope_Table.Table (S).From_Xref := From;
643 SPARK_Scope_Table.Table (S).To_Xref := To;
644 end Update_Scope_Range;
646 -- Local variables
648 Col : Nat;
649 From_Index : Xref_Index;
650 Line : Nat;
651 Loc : Source_Ptr;
652 Prev_Typ : Character;
653 Ref_Count : Nat;
654 Ref_Id : Entity_Id;
655 Ref_Name : String_Ptr;
656 Scope_Id : Scope_Index;
658 -- Start of processing for Add_SPARK_Xrefs
660 begin
661 for Index in SPARK_Scope_Table.First .. SPARK_Scope_Table.Last loop
662 declare
663 S : SPARK_Scope_Record renames SPARK_Scope_Table.Table (Index);
664 begin
665 Set_Scope_Num (S.Scope_Entity, S.Scope_Num);
666 end;
667 end loop;
669 -- Set up the pointer vector for the sort
671 for Index in 1 .. Nrefs loop
672 Rnums (Index) := Index;
673 end loop;
675 for Index in Drefs.First .. Drefs.Last loop
676 Xrefs.Append (Drefs.Table (Index));
678 Nrefs := Nrefs + 1;
679 Rnums (Nrefs) := Xrefs.Last;
680 end loop;
682 -- Capture the definition Sloc values. As in the case of normal cross
683 -- references, we have to wait until now to get the correct value.
685 for Index in 1 .. Nrefs loop
686 Xrefs.Table (Index).Def := Sloc (Xrefs.Table (Index).Key.Ent);
687 end loop;
689 -- Eliminate entries not appropriate for SPARK. Done prior to sorting
690 -- cross-references, as it discards useless references which do not have
691 -- a proper format for the comparison function (like no location).
693 Ref_Count := Nrefs;
694 Nrefs := 0;
696 for Index in 1 .. Ref_Count loop
697 declare
698 Ref : Xref_Key renames Xrefs.Table (Rnums (Index)).Key;
700 begin
701 if SPARK_Entities (Ekind (Ref.Ent))
702 and then SPARK_References (Ref.Typ)
703 and then Is_SPARK_Scope (Ref.Ent_Scope)
704 and then Is_SPARK_Scope (Ref.Ref_Scope)
705 and then Is_SPARK_Reference (Ref.Ent, Ref.Typ)
707 -- Discard references from unknown scopes, e.g. generic scopes
709 and then Get_Scope_Num (Ref.Ent_Scope) /= No_Scope
710 and then Get_Scope_Num (Ref.Ref_Scope) /= No_Scope
711 then
712 Nrefs := Nrefs + 1;
713 Rnums (Nrefs) := Rnums (Index);
714 end if;
715 end;
716 end loop;
718 -- Sort the references
720 Sorting.Sort (Integer (Nrefs));
722 -- Eliminate duplicate entries
724 -- We need this test for Ref_Count because if we force ALI file
725 -- generation in case of errors detected, it may be the case that
726 -- Nrefs is 0, so we should not reset it here.
728 if Nrefs >= 2 then
729 Ref_Count := Nrefs;
730 Nrefs := 1;
732 for Index in 2 .. Ref_Count loop
733 if Xrefs.Table (Rnums (Index)) /=
734 Xrefs.Table (Rnums (Nrefs))
735 then
736 Nrefs := Nrefs + 1;
737 Rnums (Nrefs) := Rnums (Index);
738 end if;
739 end loop;
740 end if;
742 -- Eliminate the reference if it is at the same location as the previous
743 -- one, unless it is a read-reference indicating that the entity is an
744 -- in-out actual in a call.
746 Ref_Count := Nrefs;
747 Nrefs := 0;
748 Loc := No_Location;
749 Prev_Typ := 'm';
751 for Index in 1 .. Ref_Count loop
752 declare
753 Ref : Xref_Key renames Xrefs.Table (Rnums (Index)).Key;
755 begin
756 if Ref.Loc /= Loc
757 or else (Prev_Typ = 'm' and then Ref.Typ = 'r')
758 then
759 Loc := Ref.Loc;
760 Prev_Typ := Ref.Typ;
761 Nrefs := Nrefs + 1;
762 Rnums (Nrefs) := Rnums (Index);
763 end if;
764 end;
765 end loop;
767 -- The two steps have eliminated all references, nothing to do
769 if SPARK_Scope_Table.Last = 0 then
770 return;
771 end if;
773 Ref_Id := Empty;
774 Scope_Id := 1;
775 From_Index := 1;
777 -- Loop to output references
779 for Refno in 1 .. Nrefs loop
780 declare
781 Ref_Entry : Xref_Entry renames Xrefs.Table (Rnums (Refno));
782 Ref : Xref_Key renames Ref_Entry.Key;
783 Typ : Character;
785 begin
786 -- If this assertion fails, the scope which we are looking for is
787 -- not in SPARK scope table, which reveals either a problem in the
788 -- construction of the scope table, or an erroneous scope for the
789 -- current cross-reference.
791 pragma Assert (Is_Future_Scope_Entity (Ref.Ent_Scope, Scope_Id));
793 -- Update the range of cross references to which the current scope
794 -- refers to. This may be the empty range only for the first scope
795 -- considered.
797 if Ref.Ent_Scope /= Entity_Of_Scope (Scope_Id) then
798 Update_Scope_Range
799 (S => Scope_Id,
800 From => From_Index,
801 To => SPARK_Xref_Table.Last);
803 From_Index := SPARK_Xref_Table.Last + 1;
804 end if;
806 while Ref.Ent_Scope /= Entity_Of_Scope (Scope_Id) loop
807 Scope_Id := Scope_Id + 1;
808 pragma Assert (Scope_Id <= SPARK_Scope_Table.Last);
809 end loop;
811 if Ref.Ent /= Ref_Id then
812 Ref_Name := new String'(Unique_Name (Ref.Ent));
813 end if;
815 if Ref.Ent = Heap then
816 Line := 0;
817 Col := 0;
818 else
819 Line := Int (Get_Logical_Line_Number (Ref_Entry.Def));
820 Col := Int (Get_Column_Number (Ref_Entry.Def));
821 end if;
823 -- References to constant objects are considered specially in
824 -- SPARK section, because these will be translated as constants in
825 -- the intermediate language for formal verification, and should
826 -- therefore never appear in frame conditions.
828 if Is_Constant_Object (Ref.Ent) then
829 Typ := 'c';
830 else
831 Typ := Ref.Typ;
832 end if;
834 SPARK_Xref_Table.Append (
835 (Entity_Name => Ref_Name,
836 Entity_Line => Line,
837 Etype => Get_Entity_Type (Ref.Ent),
838 Entity_Col => Col,
839 File_Num => Dependency_Num (Ref.Lun),
840 Scope_Num => Get_Scope_Num (Ref.Ref_Scope),
841 Line => Int (Get_Logical_Line_Number (Ref.Loc)),
842 Rtype => Typ,
843 Col => Int (Get_Column_Number (Ref.Loc))));
844 end;
845 end loop;
847 -- Update the range of cross references to which the scope refers to
849 Update_Scope_Range
850 (S => Scope_Id,
851 From => From_Index,
852 To => SPARK_Xref_Table.Last);
853 end Add_SPARK_Xrefs;
855 -------------------------
856 -- Collect_SPARK_Xrefs --
857 -------------------------
859 procedure Collect_SPARK_Xrefs
860 (Sdep_Table : Unit_Ref_Table;
861 Num_Sdep : Nat)
863 D1 : Nat;
864 D2 : Nat;
866 begin
867 -- Cross-references should have been computed first
869 pragma Assert (Xrefs.Last /= 0);
871 Initialize_SPARK_Tables;
873 -- Generate file and scope SPARK cross-reference information
875 D1 := 1;
876 while D1 <= Num_Sdep loop
878 -- In rare cases, when treating the library-level instantiation of a
879 -- generic, two consecutive units refer to the same compilation unit
880 -- node and entity. In that case, treat them as a single unit for the
881 -- sake of SPARK cross references by passing to Add_SPARK_File.
883 if D1 < Num_Sdep
884 and then Cunit_Entity (Sdep_Table (D1)) =
885 Cunit_Entity (Sdep_Table (D1 + 1))
886 then
887 D2 := D1 + 1;
888 else
889 D2 := D1;
890 end if;
892 -- Some files do not correspond to Ada units, and as such present no
893 -- interest for SPARK cross references. Skip these files, as printing
894 -- their name may require printing the full name with spaces, which
895 -- is not handled in the code doing I/O of SPARK cross references.
897 if Present (Cunit_Entity (Sdep_Table (D1))) then
898 Add_SPARK_File
899 (Ubody => Sdep_Table (D1),
900 Uspec => Sdep_Table (D2),
901 Dspec => D2);
902 end if;
904 D1 := D2 + 1;
905 end loop;
907 -- Fill in the spec information when relevant
909 declare
910 package Entity_Hash_Table is new
911 GNAT.HTable.Simple_HTable
912 (Header_Num => Entity_Hashed_Range,
913 Element => Scope_Index,
914 No_Element => 0,
915 Key => Entity_Id,
916 Hash => Entity_Hash,
917 Equal => "=");
919 begin
920 -- Fill in the hash-table
922 for S in SPARK_Scope_Table.First .. SPARK_Scope_Table.Last loop
923 declare
924 Srec : SPARK_Scope_Record renames SPARK_Scope_Table.Table (S);
925 begin
926 Entity_Hash_Table.Set (Srec.Scope_Entity, S);
927 end;
928 end loop;
930 -- Use the hash-table to locate spec entities
932 for S in SPARK_Scope_Table.First .. SPARK_Scope_Table.Last loop
933 declare
934 Srec : SPARK_Scope_Record renames SPARK_Scope_Table.Table (S);
936 Spec_Entity : constant Entity_Id :=
937 Unique_Entity (Srec.Scope_Entity);
938 Spec_Scope : constant Scope_Index :=
939 Entity_Hash_Table.Get (Spec_Entity);
941 begin
942 -- Generic spec may be missing in which case Spec_Scope is zero
944 if Spec_Entity /= Srec.Scope_Entity
945 and then Spec_Scope /= 0
946 then
947 Srec.Spec_File_Num :=
948 SPARK_Scope_Table.Table (Spec_Scope).File_Num;
949 Srec.Spec_Scope_Num :=
950 SPARK_Scope_Table.Table (Spec_Scope).Scope_Num;
951 end if;
952 end;
953 end loop;
954 end;
956 -- Generate SPARK cross-reference information
958 Add_SPARK_Xrefs;
959 end Collect_SPARK_Xrefs;
961 --------------------------------
962 -- Detect_And_Add_SPARK_Scope --
963 --------------------------------
965 procedure Detect_And_Add_SPARK_Scope (N : Node_Id) is
966 begin
967 if Nkind_In (N, N_Subprogram_Declaration,
968 N_Subprogram_Body,
969 N_Subprogram_Body_Stub,
970 N_Package_Declaration,
971 N_Package_Body)
972 then
973 Add_SPARK_Scope (N);
974 end if;
975 end Detect_And_Add_SPARK_Scope;
977 -------------------------------------
978 -- Enclosing_Subprogram_Or_Package --
979 -------------------------------------
981 function Enclosing_Subprogram_Or_Library_Package
982 (N : Node_Id) return Entity_Id
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 =>
1002 -- Only return a library-level package
1004 if Is_Library_Level_Entity (Defining_Entity (Result)) then
1005 Result := Defining_Entity (Result);
1006 exit;
1007 else
1008 Result := Parent (Result);
1009 end if;
1011 when N_Package_Body =>
1013 -- Only return a library-level package
1015 if Is_Library_Level_Entity (Defining_Entity (Result)) then
1016 Result := Defining_Entity (Result);
1017 exit;
1018 else
1019 Result := Parent (Result);
1020 end if;
1022 when N_Subprogram_Specification =>
1023 Result := Defining_Unit_Name (Result);
1024 exit;
1026 when N_Subprogram_Declaration =>
1027 Result := Defining_Unit_Name (Specification (Result));
1028 exit;
1030 when N_Subprogram_Body =>
1031 Result := Defining_Unit_Name (Specification (Result));
1032 exit;
1034 when N_Pragma =>
1036 -- The enclosing subprogram for a precondition, postcondition,
1037 -- or contract case should be the declaration preceding the
1038 -- pragma (skipping any other pragmas between this pragma and
1039 -- this declaration.
1041 while Nkind (Result) = N_Pragma
1042 and then Is_List_Member (Result)
1043 and then Present (Prev (Result))
1044 loop
1045 Result := Prev (Result);
1046 end loop;
1048 if Nkind (Result) = N_Pragma then
1049 Result := Parent (Result);
1050 end if;
1052 when others =>
1053 Result := Parent (Result);
1054 end case;
1055 end loop;
1057 if Nkind (Result) = N_Defining_Program_Unit_Name then
1058 Result := Defining_Identifier (Result);
1059 end if;
1061 -- Do not return a scope without a proper location
1063 if Present (Result)
1064 and then Sloc (Result) = No_Location
1065 then
1066 return Empty;
1067 end if;
1069 return Result;
1070 end Enclosing_Subprogram_Or_Library_Package;
1072 -----------------
1073 -- Entity_Hash --
1074 -----------------
1076 function Entity_Hash (E : Entity_Id) return Entity_Hashed_Range is
1077 begin
1078 return
1079 Entity_Hashed_Range (E mod (Entity_Id (Entity_Hashed_Range'Last) + 1));
1080 end Entity_Hash;
1082 --------------------------
1083 -- Generate_Dereference --
1084 --------------------------
1086 procedure Generate_Dereference
1087 (N : Node_Id;
1088 Typ : Character := 'r')
1090 procedure Create_Heap;
1091 -- Create and decorate the special entity which denotes the heap
1093 -----------------
1094 -- Create_Heap --
1095 -----------------
1097 procedure Create_Heap is
1098 begin
1099 Name_Len := Name_Of_Heap_Variable'Length;
1100 Name_Buffer (1 .. Name_Len) := Name_Of_Heap_Variable;
1102 Heap := Make_Defining_Identifier (Standard_Location, Name_Enter);
1104 Set_Ekind (Heap, E_Variable);
1105 Set_Is_Internal (Heap, True);
1106 Set_Has_Fully_Qualified_Name (Heap);
1107 end Create_Heap;
1109 -- Local variables
1111 Loc : constant Source_Ptr := Sloc (N);
1112 Index : Nat;
1113 Ref_Scope : Entity_Id;
1115 -- Start of processing for Generate_Dereference
1117 begin
1119 if Loc > No_Location then
1120 Drefs.Increment_Last;
1121 Index := Drefs.Last;
1123 declare
1124 Deref_Entry : Xref_Entry renames Drefs.Table (Index);
1125 Deref : Xref_Key renames Deref_Entry.Key;
1127 begin
1128 if No (Heap) then
1129 Create_Heap;
1130 end if;
1132 Ref_Scope := Enclosing_Subprogram_Or_Library_Package (N);
1134 Deref.Ent := Heap;
1135 Deref.Loc := Loc;
1136 Deref.Typ := Typ;
1138 -- It is as if the special "Heap" was defined in every scope where
1139 -- it is referenced.
1141 Deref.Eun := Get_Code_Unit (Loc);
1142 Deref.Lun := Get_Code_Unit (Loc);
1144 Deref.Ref_Scope := Ref_Scope;
1145 Deref.Ent_Scope := Ref_Scope;
1147 Deref_Entry.Def := No_Location;
1149 Deref_Entry.Ent_Scope_File := Get_Code_Unit (N);
1150 end;
1151 end if;
1152 end Generate_Dereference;
1154 ------------------------------------
1155 -- Traverse_All_Compilation_Units --
1156 ------------------------------------
1158 procedure Traverse_All_Compilation_Units (Process : Node_Processing) is
1159 begin
1160 for U in Units.First .. Last_Unit loop
1161 Traverse_Compilation_Unit (Cunit (U), Process, Inside_Stubs => False);
1162 end loop;
1163 end Traverse_All_Compilation_Units;
1165 -------------------------------
1166 -- Traverse_Compilation_Unit --
1167 -------------------------------
1169 procedure Traverse_Compilation_Unit
1170 (CU : Node_Id;
1171 Process : Node_Processing;
1172 Inside_Stubs : Boolean)
1174 Lu : Node_Id;
1176 begin
1177 -- Get Unit (checking case of subunit)
1179 Lu := Unit (CU);
1181 if Nkind (Lu) = N_Subunit then
1182 Lu := Proper_Body (Lu);
1183 end if;
1185 -- Do not add scopes for generic units
1187 if Nkind (Lu) = N_Package_Body
1188 and then Ekind (Corresponding_Spec (Lu)) in Generic_Unit_Kind
1189 then
1190 return;
1191 end if;
1193 -- Call Process on all declarations
1195 if Nkind (Lu) in N_Declaration
1196 or else Nkind (Lu) in N_Later_Decl_Item
1197 then
1198 Process (Lu);
1199 end if;
1201 -- Traverse the unit
1203 if Nkind (Lu) = N_Subprogram_Body then
1204 Traverse_Subprogram_Body (Lu, Process, Inside_Stubs);
1206 elsif Nkind (Lu) = N_Subprogram_Declaration then
1207 null;
1209 elsif Nkind (Lu) = N_Package_Declaration then
1210 Traverse_Package_Declaration (Lu, Process, Inside_Stubs);
1212 elsif Nkind (Lu) = N_Package_Body then
1213 Traverse_Package_Body (Lu, Process, Inside_Stubs);
1215 -- All other cases of compilation units (e.g. renamings), are not
1216 -- declarations, or else generic declarations which are ignored.
1218 else
1219 null;
1220 end if;
1221 end Traverse_Compilation_Unit;
1223 -----------------------------------------
1224 -- Traverse_Declarations_Or_Statements --
1225 -----------------------------------------
1227 procedure Traverse_Declarations_Or_Statements
1228 (L : List_Id;
1229 Process : Node_Processing;
1230 Inside_Stubs : Boolean)
1232 N : Node_Id;
1234 begin
1235 -- Loop through statements or declarations
1237 N := First (L);
1238 while Present (N) loop
1239 -- Call Process on all declarations
1241 if Nkind (N) in N_Declaration
1242 or else
1243 Nkind (N) in N_Later_Decl_Item
1244 then
1245 Process (N);
1246 end if;
1248 case Nkind (N) is
1250 -- Package declaration
1252 when N_Package_Declaration =>
1253 Traverse_Package_Declaration (N, Process, Inside_Stubs);
1255 -- Package body
1257 when N_Package_Body =>
1258 if Ekind (Defining_Entity (N)) /= E_Generic_Package then
1259 Traverse_Package_Body (N, Process, Inside_Stubs);
1260 end if;
1262 when N_Package_Body_Stub =>
1263 if Present (Library_Unit (N)) then
1264 declare
1265 Body_N : constant Node_Id := Get_Body_From_Stub (N);
1266 begin
1267 if Inside_Stubs
1268 and then
1269 Ekind (Defining_Entity (Body_N)) /= E_Generic_Package
1270 then
1271 Traverse_Package_Body (Body_N, Process, Inside_Stubs);
1272 end if;
1273 end;
1274 end if;
1276 -- Subprogram declaration
1278 when N_Subprogram_Declaration =>
1279 null;
1281 -- Subprogram body
1283 when N_Subprogram_Body =>
1284 if not Is_Generic_Subprogram (Defining_Entity (N)) then
1285 Traverse_Subprogram_Body (N, Process, Inside_Stubs);
1286 end if;
1288 when N_Subprogram_Body_Stub =>
1289 if Present (Library_Unit (N)) then
1290 declare
1291 Body_N : constant Node_Id := Get_Body_From_Stub (N);
1292 begin
1293 if Inside_Stubs
1294 and then
1295 not Is_Generic_Subprogram (Defining_Entity (Body_N))
1296 then
1297 Traverse_Subprogram_Body
1298 (Body_N, Process, Inside_Stubs);
1299 end if;
1300 end;
1301 end if;
1303 -- Block statement
1305 when N_Block_Statement =>
1306 Traverse_Declarations_Or_Statements
1307 (Declarations (N), Process, Inside_Stubs);
1308 Traverse_Handled_Statement_Sequence
1309 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1311 when N_If_Statement =>
1313 -- Traverse the statements in the THEN part
1315 Traverse_Declarations_Or_Statements
1316 (Then_Statements (N), Process, Inside_Stubs);
1318 -- Loop through ELSIF parts if present
1320 if Present (Elsif_Parts (N)) then
1321 declare
1322 Elif : Node_Id := First (Elsif_Parts (N));
1324 begin
1325 while Present (Elif) loop
1326 Traverse_Declarations_Or_Statements
1327 (Then_Statements (Elif), Process, Inside_Stubs);
1328 Next (Elif);
1329 end loop;
1330 end;
1331 end if;
1333 -- Finally traverse the ELSE statements if present
1335 Traverse_Declarations_Or_Statements
1336 (Else_Statements (N), Process, Inside_Stubs);
1338 -- Case statement
1340 when N_Case_Statement =>
1342 -- Process case branches
1344 declare
1345 Alt : Node_Id;
1346 begin
1347 Alt := First (Alternatives (N));
1348 while Present (Alt) loop
1349 Traverse_Declarations_Or_Statements
1350 (Statements (Alt), Process, Inside_Stubs);
1351 Next (Alt);
1352 end loop;
1353 end;
1355 -- Extended return statement
1357 when N_Extended_Return_Statement =>
1358 Traverse_Handled_Statement_Sequence
1359 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1361 -- Loop
1363 when N_Loop_Statement =>
1364 Traverse_Declarations_Or_Statements
1365 (Statements (N), Process, Inside_Stubs);
1367 -- Generic declarations are ignored
1369 when others =>
1370 null;
1371 end case;
1373 Next (N);
1374 end loop;
1375 end Traverse_Declarations_Or_Statements;
1377 -----------------------------------------
1378 -- Traverse_Handled_Statement_Sequence --
1379 -----------------------------------------
1381 procedure Traverse_Handled_Statement_Sequence
1382 (N : Node_Id;
1383 Process : Node_Processing;
1384 Inside_Stubs : Boolean)
1386 Handler : Node_Id;
1388 begin
1389 if Present (N) then
1390 Traverse_Declarations_Or_Statements
1391 (Statements (N), Process, Inside_Stubs);
1393 if Present (Exception_Handlers (N)) then
1394 Handler := First (Exception_Handlers (N));
1395 while Present (Handler) loop
1396 Traverse_Declarations_Or_Statements
1397 (Statements (Handler), Process, Inside_Stubs);
1398 Next (Handler);
1399 end loop;
1400 end if;
1401 end if;
1402 end Traverse_Handled_Statement_Sequence;
1404 ---------------------------
1405 -- Traverse_Package_Body --
1406 ---------------------------
1408 procedure Traverse_Package_Body
1409 (N : Node_Id;
1410 Process : Node_Processing;
1411 Inside_Stubs : Boolean) is
1412 begin
1413 Traverse_Declarations_Or_Statements
1414 (Declarations (N), Process, Inside_Stubs);
1415 Traverse_Handled_Statement_Sequence
1416 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1417 end Traverse_Package_Body;
1419 ----------------------------------
1420 -- Traverse_Package_Declaration --
1421 ----------------------------------
1423 procedure Traverse_Package_Declaration
1424 (N : Node_Id;
1425 Process : Node_Processing;
1426 Inside_Stubs : Boolean)
1428 Spec : constant Node_Id := Specification (N);
1429 begin
1430 Traverse_Declarations_Or_Statements
1431 (Visible_Declarations (Spec), Process, Inside_Stubs);
1432 Traverse_Declarations_Or_Statements
1433 (Private_Declarations (Spec), Process, Inside_Stubs);
1434 end Traverse_Package_Declaration;
1436 ------------------------------
1437 -- Traverse_Subprogram_Body --
1438 ------------------------------
1440 procedure Traverse_Subprogram_Body
1441 (N : Node_Id;
1442 Process : Node_Processing;
1443 Inside_Stubs : Boolean)
1445 begin
1446 Traverse_Declarations_Or_Statements
1447 (Declarations (N), Process, Inside_Stubs);
1448 Traverse_Handled_Statement_Sequence
1449 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1450 end Traverse_Subprogram_Body;
1452 end SPARK_Specific;