1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- L I B . X R E F . S P A R K _ S P E C I F I C --
9 -- Copyright (C) 2011-2016, Free Software Foundation, Inc. --
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. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
26 with Einfo; use Einfo;
27 with Nmake; use Nmake;
28 with SPARK_Xrefs; use SPARK_Xrefs;
33 package body SPARK_Specific is
39 -- Table of SPARK_Entities, True for each entity kind used in SPARK
41 SPARK_Entities : constant array (Entity_Kind) of Boolean :=
45 E_In_Out_Parameter => True,
46 E_In_Parameter => True,
47 E_Loop_Parameter => True,
49 E_Out_Parameter => True,
54 -- True for each reference type used in SPARK
56 SPARK_References : constant array (Character) of Boolean :=
62 type Entity_Hashed_Range is range 0 .. 255;
63 -- Size of hash table headers
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,
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
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_Declaration_Or_Statement
110 Process : Node_Processing;
111 Inside_Stubs : Boolean);
112 procedure Traverse_Declarations_Or_Statements
114 Process : Node_Processing;
115 Inside_Stubs : Boolean);
116 procedure Traverse_Handled_Statement_Sequence
118 Process : Node_Processing;
119 Inside_Stubs : Boolean);
120 procedure Traverse_Protected_Body
122 Process : Node_Processing;
123 Inside_Stubs : Boolean);
124 procedure Traverse_Package_Body
126 Process : Node_Processing;
127 Inside_Stubs : Boolean);
128 procedure Traverse_Subprogram_Body
130 Process : Node_Processing;
131 Inside_Stubs : Boolean);
132 -- Traverse corresponding construct, calling Process on all declarations
138 procedure Add_SPARK_File (Ubody, Uspec : Unit_Number_Type; Dspec : Nat) is
139 File : constant Source_File_Index := Source_Index (Uspec);
142 File_Name : String_Ptr;
143 Unit_File_Name : String_Ptr;
146 -- Source file could be inexistant as a result of an error, if option
149 if File = No_Source_File then
153 -- Subunits are traversed as part of the top-level unit to which they
156 if Nkind (Unit (Cunit (Ubody))) = N_Subunit then
160 From := SPARK_Scope_Table.Last + 1;
162 Traverse_Compilation_Unit
163 (CU => Cunit (Ubody),
164 Process => Detect_And_Add_SPARK_Scope'Access,
165 Inside_Stubs => True);
167 -- When two units are present for the same compilation unit, as it
168 -- happens for library-level instantiations of generics, then add all
169 -- scopes to the same SPARK file.
171 if Ubody /= Uspec then
172 Traverse_Compilation_Unit
173 (CU => Cunit (Uspec),
174 Process => Detect_And_Add_SPARK_Scope'Access,
175 Inside_Stubs => True);
178 -- Update scope numbers
184 for Index in From .. SPARK_Scope_Table.Last loop
186 S : SPARK_Scope_Record renames SPARK_Scope_Table.Table (Index);
188 S.Scope_Num := Scope_Id;
190 Scope_Id := Scope_Id + 1;
195 -- Make entry for new file in file table
197 Get_Name_String (Reference_Name (File));
198 File_Name := new String'(Name_Buffer (1 .. Name_Len));
200 -- For subunits, also retrieve the file name of the unit. Only do so if
201 -- unit has an associated compilation unit.
203 if Present (Cunit (Unit (File)))
204 and then Nkind (Unit (Cunit (Unit (File)))) = N_Subunit
206 Get_Name_String (Reference_Name (Main_Source_File));
207 Unit_File_Name := new String'(Name_Buffer (1 .. Name_Len));
209 Unit_File_Name := null;
212 SPARK_File_Table.Append (
213 (File_Name => File_Name,
214 Unit_File_Name => Unit_File_Name,
217 To_Scope => SPARK_Scope_Table.Last));
220 ---------------------
221 -- Add_SPARK_Scope --
222 ---------------------
224 procedure Add_SPARK_Scope (N : Node_Id) is
225 E : constant Entity_Id := Defining_Entity (N);
226 Loc : constant Source_Ptr := Sloc (E);
228 -- The character describing the kind of scope is chosen to be the same
229 -- as the one describing the corresponding entity in cross references,
230 -- see Xref_Entity_Letters in lib-xrefs.ads
235 -- Ignore scopes without a proper location
237 if Sloc (N) = No_Location then
246 | E_Generic_Procedure
251 Typ := Xref_Entity_Letters (Ekind (E));
256 -- In SPARK we need to distinguish protected functions and
257 -- procedures from ordinary subprograms, but there are no special
258 -- Xref letters for them. Since this distiction is only needed
259 -- to detect protected calls, we pretend that such calls are entry
262 if Ekind (Scope (E)) = E_Protected_Type then
263 Typ := Xref_Entity_Letters (E_Entry);
265 Typ := Xref_Entity_Letters (Ekind (E));
273 Typ := Xref_Entity_Letters (Ekind (Unique_Entity (E)));
277 -- Compilation of prj-attr.adb with -gnatn creates a node with
278 -- entity E_Void for the package defined at a-charac.ads16:13.
287 -- File_Num and Scope_Num are filled later. From_Xref and To_Xref are
288 -- filled even later, but are initialized to represent an empty range.
290 SPARK_Scope_Table.Append (
291 (Scope_Name => new String'(Unique_Name (E)),
296 Line => Nat (Get_Logical_Line_Number (Loc)),
298 Col => Nat (Get_Column_Number (Loc)),
304 ---------------------
305 -- Add_SPARK_Xrefs --
306 ---------------------
308 procedure Add_SPARK_Xrefs is
309 function Entity_Of_Scope (S : Scope_Index) return Entity_Id;
310 -- Return the entity which maps to the input scope index
312 function Get_Entity_Type (E : Entity_Id) return Character;
313 -- Return a character representing the type of entity
315 function Is_Constant_Object_Without_Variable_Input
316 (E : Entity_Id) return Boolean;
317 -- Return True if E is known to have no variable input, as defined in
320 function Is_Future_Scope_Entity
322 S : Scope_Index) return Boolean;
323 -- Check whether entity E is in SPARK_Scope_Table at index S or higher
325 function Is_SPARK_Reference
327 Typ : Character) return Boolean;
328 -- Return whether entity reference E meets SPARK requirements. Typ is
329 -- the reference type.
331 function Is_SPARK_Scope (E : Entity_Id) return Boolean;
332 -- Return whether the entity or reference scope meets requirements for
333 -- being a SPARK scope.
335 function Lt (Op1 : Natural; Op2 : Natural) return Boolean;
336 -- Comparison function for Sort call
338 procedure Move (From : Natural; To : Natural);
339 -- Move procedure for Sort call
341 procedure Update_Scope_Range
345 -- Update the scope which maps to S with the new range From .. To
347 package Sorting is new GNAT.Heap_Sort_G (Move, Lt);
349 function Get_Scope_Num (N : Entity_Id) return Nat;
350 -- Return the scope number associated to entity N
352 procedure Set_Scope_Num (N : Entity_Id; Num : Nat);
353 -- Associate entity N to scope number Num
355 No_Scope : constant Nat := 0;
356 -- Initial scope counter
358 type Scope_Rec is record
362 -- Type used to relate an entity and a scope number
364 package Scopes is new GNAT.HTable.Simple_HTable
365 (Header_Num => Entity_Hashed_Range,
366 Element => Scope_Rec,
367 No_Element => (Num => No_Scope, Entity => Empty),
371 -- Package used to build a correspondence between entities and scope
372 -- numbers used in SPARK cross references.
374 Nrefs : Nat := Xrefs.Last;
375 -- Number of references in table. This value may get reset (reduced)
376 -- when we eliminate duplicate reference entries as well as references
377 -- not suitable for local cross-references.
379 Nrefs_Add : constant Nat := Drefs.Last;
380 -- Number of additional references which correspond to dereferences in
383 Rnums : array (0 .. Nrefs + Nrefs_Add) of Nat;
384 -- This array contains numbers of references in the Xrefs table. This
385 -- list is sorted in output order. The extra 0'th entry is convenient
386 -- for the call to sort. When we sort the table, we move the entries in
387 -- Rnums around, but we do not move the original table entries.
389 ---------------------
390 -- Entity_Of_Scope --
391 ---------------------
393 function Entity_Of_Scope (S : Scope_Index) return Entity_Id is
395 return SPARK_Scope_Table.Table (S).Scope_Entity;
398 ---------------------
399 -- Get_Entity_Type --
400 ---------------------
402 function Get_Entity_Type (E : Entity_Id) return Character is
405 when E_Out_Parameter => return '<';
406 when E_In_Out_Parameter => return '=';
407 when E_In_Parameter => return '>';
408 when others => return '*';
416 function Get_Scope_Num (N : Entity_Id) return Nat is
418 return Scopes.Get (N).Num;
421 -----------------------------------------------
422 -- Is_Constant_Object_Without_Variable_Input --
423 -----------------------------------------------
425 function Is_Constant_Object_Without_Variable_Input
426 (E : Entity_Id) return Boolean
433 -- A constant is known to have no variable input if its
434 -- initializing expression is static (a value which is
435 -- compile-time-known is not guaranteed to have no variable input
436 -- as defined in the SPARK RM). Otherwise, the constant may or not
437 -- have variable input.
443 if Present (Full_View (E)) then
444 Decl := Parent (Full_View (E));
449 if Is_Imported (E) then
452 pragma Assert (Present (Expression (Decl)));
453 Result := Is_Static_Expression (Expression (Decl));
457 when E_Loop_Parameter | E_In_Parameter =>
465 end Is_Constant_Object_Without_Variable_Input;
467 ----------------------------
468 -- Is_Future_Scope_Entity --
469 ----------------------------
471 function Is_Future_Scope_Entity
473 S : Scope_Index) return Boolean
475 function Is_Past_Scope_Entity return Boolean;
476 -- Check whether entity E is in SPARK_Scope_Table at index strictly
479 --------------------------
480 -- Is_Past_Scope_Entity --
481 --------------------------
483 function Is_Past_Scope_Entity return Boolean is
485 for Index in SPARK_Scope_Table.First .. S - 1 loop
486 if SPARK_Scope_Table.Table (Index).Scope_Entity = E then
492 end Is_Past_Scope_Entity;
494 -- Start of processing for Is_Future_Scope_Entity
497 for Index in S .. SPARK_Scope_Table.Last loop
498 if SPARK_Scope_Table.Table (Index).Scope_Entity = E then
503 -- If this assertion fails, this means that the scope which we are
504 -- looking for has been treated already, which reveals a problem in
505 -- the order of cross-references.
507 pragma Assert (not Is_Past_Scope_Entity);
510 end Is_Future_Scope_Entity;
512 ------------------------
513 -- Is_SPARK_Reference --
514 ------------------------
516 function Is_SPARK_Reference
518 Typ : Character) return Boolean
521 -- The only references of interest on callable entities are calls. On
522 -- uncallable entities, the only references of interest are reads and
525 if Ekind (E) in Overloadable_Kind then
528 -- Objects of task or protected types are not SPARK references
530 elsif Present (Etype (E))
531 and then Ekind (Etype (E)) in Concurrent_Kind
535 -- In all other cases, result is true for reference/modify cases,
536 -- and false for all other cases.
539 return Typ = 'r' or else Typ = 'm';
541 end Is_SPARK_Reference;
547 function Is_SPARK_Scope (E : Entity_Id) return Boolean is
550 and then not Is_Generic_Unit (E)
551 and then Renamed_Entity (E) = Empty
552 and then Get_Scope_Num (E) /= No_Scope;
559 function Lt (Op1, Op2 : Natural) return Boolean is
560 T1 : constant Xref_Entry := Xrefs.Table (Rnums (Nat (Op1)));
561 T2 : constant Xref_Entry := Xrefs.Table (Rnums (Nat (Op2)));
564 -- First test: if entity is in different unit, sort by unit. Note:
565 -- that we use Ent_Scope_File rather than Eun, as Eun may refer to
566 -- the file where the generic scope is defined, which may differ from
567 -- the file where the enclosing scope is defined. It is the latter
568 -- which matters for a correct order here.
570 if T1.Ent_Scope_File /= T2.Ent_Scope_File then
571 return Dependency_Num (T1.Ent_Scope_File) <
572 Dependency_Num (T2.Ent_Scope_File);
574 -- Second test: within same unit, sort by location of the scope of
575 -- the entity definition.
577 elsif Get_Scope_Num (T1.Key.Ent_Scope) /=
578 Get_Scope_Num (T2.Key.Ent_Scope)
580 return Get_Scope_Num (T1.Key.Ent_Scope) <
581 Get_Scope_Num (T2.Key.Ent_Scope);
583 -- Third test: within same unit and scope, sort by location of
584 -- entity definition.
586 elsif T1.Def /= T2.Def then
587 return T1.Def < T2.Def;
590 -- Both entities must be equal at this point
592 pragma Assert (T1.Key.Ent = T2.Key.Ent);
593 pragma Assert (T1.Key.Ent_Scope = T2.Key.Ent_Scope);
594 pragma Assert (T1.Ent_Scope_File = T2.Ent_Scope_File);
596 -- Fourth test: if reference is in same unit as entity definition,
599 if T1.Key.Lun /= T2.Key.Lun
600 and then T1.Ent_Scope_File = T1.Key.Lun
604 elsif T1.Key.Lun /= T2.Key.Lun
605 and then T2.Ent_Scope_File = T2.Key.Lun
609 -- Fifth test: if reference is in same unit and same scope as
610 -- entity definition, sort first.
612 elsif T1.Ent_Scope_File = T1.Key.Lun
613 and then T1.Key.Ref_Scope /= T2.Key.Ref_Scope
614 and then T1.Key.Ent_Scope = T1.Key.Ref_Scope
618 elsif T2.Ent_Scope_File = T2.Key.Lun
619 and then T1.Key.Ref_Scope /= T2.Key.Ref_Scope
620 and then T2.Key.Ent_Scope = T2.Key.Ref_Scope
624 -- Sixth test: for same entity, sort by reference location unit
626 elsif T1.Key.Lun /= T2.Key.Lun then
627 return Dependency_Num (T1.Key.Lun) <
628 Dependency_Num (T2.Key.Lun);
630 -- Seventh test: for same entity, sort by reference location scope
632 elsif Get_Scope_Num (T1.Key.Ref_Scope) /=
633 Get_Scope_Num (T2.Key.Ref_Scope)
635 return Get_Scope_Num (T1.Key.Ref_Scope) <
636 Get_Scope_Num (T2.Key.Ref_Scope);
638 -- Eighth test: order of location within referencing unit
640 elsif T1.Key.Loc /= T2.Key.Loc then
641 return T1.Key.Loc < T2.Key.Loc;
643 -- Finally, for two locations at the same address prefer the one
644 -- that does NOT have the type 'r', so that a modification or
645 -- extension takes preference, when there are more than one
646 -- reference at the same location. As a result, in the case of
647 -- entities that are in-out actuals, the read reference follows
648 -- the modify reference.
651 return T2.Key.Typ = 'r';
660 procedure Move (From : Natural; To : Natural) is
662 Rnums (Nat (To)) := Rnums (Nat (From));
669 procedure Set_Scope_Num (N : Entity_Id; Num : Nat) is
671 Scopes.Set (K => N, E => Scope_Rec'(Num => Num, Entity => N));
674 ------------------------
675 -- Update_Scope_Range --
676 ------------------------
678 procedure Update_Scope_Range
684 SPARK_Scope_Table.Table (S).From_Xref := From;
685 SPARK_Scope_Table.Table (S).To_Xref := To;
686 end Update_Scope_Range;
691 From_Index : Xref_Index;
694 Prev_Typ : Character;
697 Ref_Name : String_Ptr;
698 Scope_Id : Scope_Index;
700 -- Start of processing for Add_SPARK_Xrefs
703 for Index in SPARK_Scope_Table.First .. SPARK_Scope_Table.Last loop
705 S : SPARK_Scope_Record renames SPARK_Scope_Table.Table (Index);
707 Set_Scope_Num (S.Scope_Entity, S.Scope_Num);
711 -- Set up the pointer vector for the sort
713 for Index in 1 .. Nrefs loop
714 Rnums (Index) := Index;
717 for Index in Drefs.First .. Drefs.Last loop
718 Xrefs.Append (Drefs.Table (Index));
721 Rnums (Nrefs) := Xrefs.Last;
724 -- Capture the definition Sloc values. As in the case of normal cross
725 -- references, we have to wait until now to get the correct value.
727 for Index in 1 .. Nrefs loop
728 Xrefs.Table (Index).Def := Sloc (Xrefs.Table (Index).Key.Ent);
731 -- Eliminate entries not appropriate for SPARK. Done prior to sorting
732 -- cross-references, as it discards useless references which do not have
733 -- a proper format for the comparison function (like no location).
738 for Index in 1 .. Ref_Count loop
740 Ref : Xref_Key renames Xrefs.Table (Rnums (Index)).Key;
743 if SPARK_Entities (Ekind (Ref.Ent))
744 and then SPARK_References (Ref.Typ)
745 and then Is_SPARK_Scope (Ref.Ent_Scope)
746 and then Is_SPARK_Scope (Ref.Ref_Scope)
747 and then Is_SPARK_Reference (Ref.Ent, Ref.Typ)
749 -- Discard references from unknown scopes, e.g. generic scopes
751 and then Get_Scope_Num (Ref.Ent_Scope) /= No_Scope
752 and then Get_Scope_Num (Ref.Ref_Scope) /= No_Scope
755 Rnums (Nrefs) := Rnums (Index);
760 -- Sort the references
762 Sorting.Sort (Integer (Nrefs));
764 -- Eliminate duplicate entries
766 -- We need this test for Ref_Count because if we force ALI file
767 -- generation in case of errors detected, it may be the case that
768 -- Nrefs is 0, so we should not reset it here.
774 for Index in 2 .. Ref_Count loop
775 if Xrefs.Table (Rnums (Index)) /=
776 Xrefs.Table (Rnums (Nrefs))
779 Rnums (Nrefs) := Rnums (Index);
784 -- Eliminate the reference if it is at the same location as the previous
785 -- one, unless it is a read-reference indicating that the entity is an
786 -- in-out actual in a call.
793 for Index in 1 .. Ref_Count loop
795 Ref : Xref_Key renames Xrefs.Table (Rnums (Index)).Key;
799 or else (Prev_Typ = 'm' and then Ref.Typ = 'r')
804 Rnums (Nrefs) := Rnums (Index);
809 -- The two steps have eliminated all references, nothing to do
811 if SPARK_Scope_Table.Last = 0 then
819 -- Loop to output references
821 for Refno in 1 .. Nrefs loop
823 Ref_Entry : Xref_Entry renames Xrefs.Table (Rnums (Refno));
824 Ref : Xref_Key renames Ref_Entry.Key;
828 -- If this assertion fails, the scope which we are looking for is
829 -- not in SPARK scope table, which reveals either a problem in the
830 -- construction of the scope table, or an erroneous scope for the
831 -- current cross-reference.
833 pragma Assert (Is_Future_Scope_Entity (Ref.Ent_Scope, Scope_Id));
835 -- Update the range of cross references to which the current scope
836 -- refers to. This may be the empty range only for the first scope
839 if Ref.Ent_Scope /= Entity_Of_Scope (Scope_Id) then
843 To => SPARK_Xref_Table.Last);
845 From_Index := SPARK_Xref_Table.Last + 1;
848 while Ref.Ent_Scope /= Entity_Of_Scope (Scope_Id) loop
849 Scope_Id := Scope_Id + 1;
850 pragma Assert (Scope_Id <= SPARK_Scope_Table.Last);
853 if Ref.Ent /= Ref_Id then
854 Ref_Name := new String'(Unique_Name (Ref.Ent));
857 if Ref.Ent = Heap then
861 Line := Nat (Get_Logical_Line_Number (Ref_Entry.Def));
862 Col := Nat (Get_Column_Number (Ref_Entry.Def));
865 -- References to constant objects without variable inputs (see
866 -- SPARK RM 3.3.1) are considered specially in SPARK section,
867 -- because these will be translated as constants in the
868 -- intermediate language for formal verification, and should
869 -- therefore never appear in frame conditions. Other constants may
870 -- later be treated the same, up to GNATprove to decide based on
871 -- its flow analysis.
873 if Is_Constant_Object_Without_Variable_Input (Ref.Ent) then
879 SPARK_Xref_Table.Append (
880 (Entity_Name => Ref_Name,
882 Etype => Get_Entity_Type (Ref.Ent),
884 File_Num => Dependency_Num (Ref.Lun),
885 Scope_Num => Get_Scope_Num (Ref.Ref_Scope),
886 Line => Nat (Get_Logical_Line_Number (Ref.Loc)),
888 Col => Nat (Get_Column_Number (Ref.Loc))));
892 -- Update the range of cross references to which the scope refers to
897 To => SPARK_Xref_Table.Last);
900 -------------------------
901 -- Collect_SPARK_Xrefs --
902 -------------------------
904 procedure Collect_SPARK_Xrefs
905 (Sdep_Table : Unit_Ref_Table;
912 -- Cross-references should have been computed first
914 pragma Assert (Xrefs.Last /= 0);
916 Initialize_SPARK_Tables;
918 -- Generate file and scope SPARK cross-reference information
921 while D1 <= Num_Sdep loop
923 -- In rare cases, when treating the library-level instantiation of a
924 -- generic, two consecutive units refer to the same compilation unit
925 -- node and entity. In that case, treat them as a single unit for the
926 -- sake of SPARK cross references by passing to Add_SPARK_File.
929 and then Cunit_Entity (Sdep_Table (D1)) =
930 Cunit_Entity (Sdep_Table (D1 + 1))
937 -- Skip dependencies with no entity node, e.g. configuration files
938 -- with pragmas (.adc) or target description (.atp), since they
939 -- present no interest for SPARK cross references.
941 if Present (Cunit_Entity (Sdep_Table (D1))) then
943 (Ubody => Sdep_Table (D1),
944 Uspec => Sdep_Table (D2),
951 -- Fill in the spec information when relevant
954 package Entity_Hash_Table is new
955 GNAT.HTable.Simple_HTable
956 (Header_Num => Entity_Hashed_Range,
957 Element => Scope_Index,
964 -- Fill in the hash-table
966 for S in SPARK_Scope_Table.First .. SPARK_Scope_Table.Last loop
968 Srec : SPARK_Scope_Record renames SPARK_Scope_Table.Table (S);
970 Entity_Hash_Table.Set (Srec.Scope_Entity, S);
974 -- Use the hash-table to locate spec entities
976 for S in SPARK_Scope_Table.First .. SPARK_Scope_Table.Last loop
978 Srec : SPARK_Scope_Record renames SPARK_Scope_Table.Table (S);
980 Spec_Entity : constant Entity_Id :=
981 Unique_Entity (Srec.Scope_Entity);
982 Spec_Scope : constant Scope_Index :=
983 Entity_Hash_Table.Get (Spec_Entity);
986 -- Generic spec may be missing in which case Spec_Scope is zero
988 if Spec_Entity /= Srec.Scope_Entity
989 and then Spec_Scope /= 0
991 Srec.Spec_File_Num :=
992 SPARK_Scope_Table.Table (Spec_Scope).File_Num;
993 Srec.Spec_Scope_Num :=
994 SPARK_Scope_Table.Table (Spec_Scope).Scope_Num;
1000 -- Generate SPARK cross-reference information
1003 end Collect_SPARK_Xrefs;
1005 --------------------------------
1006 -- Detect_And_Add_SPARK_Scope --
1007 --------------------------------
1009 procedure Detect_And_Add_SPARK_Scope (N : Node_Id) is
1011 if Nkind_In (N, N_Entry_Body, -- entries
1012 N_Entry_Declaration)
1014 Nkind_In (N, N_Package_Body, -- packages
1015 N_Package_Body_Stub,
1016 N_Package_Declaration)
1018 Nkind_In (N, N_Protected_Body, -- protected objects
1019 N_Protected_Body_Stub,
1020 N_Protected_Type_Declaration)
1022 Nkind_In (N, N_Subprogram_Body, -- subprograms
1023 N_Subprogram_Body_Stub,
1024 N_Subprogram_Declaration)
1026 Nkind_In (N, N_Task_Body, -- tasks
1028 N_Task_Type_Declaration)
1030 Add_SPARK_Scope (N);
1032 end Detect_And_Add_SPARK_Scope;
1034 -------------------------------------
1035 -- Enclosing_Subprogram_Or_Package --
1036 -------------------------------------
1038 function Enclosing_Subprogram_Or_Library_Package
1039 (N : Node_Id) return Entity_Id
1041 Context : Entity_Id;
1044 -- If N is the defining identifier for a subprogram, then return the
1045 -- enclosing subprogram or package, not this subprogram.
1047 if Nkind_In (N, N_Defining_Identifier, N_Defining_Operator_Symbol)
1048 and then (Ekind (N) in Entry_Kind
1049 or else Ekind (N) = E_Subprogram_Body
1050 or else Ekind (N) in Generic_Subprogram_Kind
1051 or else Ekind (N) in Subprogram_Kind)
1053 Context := Parent (Unit_Declaration_Node (N));
1055 -- If this was a library-level subprogram then replace Context with
1056 -- its Unit, which points to N_Subprogram_* node.
1058 if Nkind (Context) = N_Compilation_Unit then
1059 Context := Unit (Context);
1065 while Present (Context) loop
1066 case Nkind (Context) is
1067 when N_Package_Body |
1068 N_Package_Specification =>
1070 -- Only return a library-level package
1072 if Is_Library_Level_Entity (Defining_Entity (Context)) then
1073 Context := Defining_Entity (Context);
1076 Context := Parent (Context);
1081 -- The enclosing subprogram for a precondition, postcondition,
1082 -- or contract case should be the declaration preceding the
1083 -- pragma (skipping any other pragmas between this pragma and
1084 -- this declaration.
1086 while Nkind (Context) = N_Pragma
1087 and then Is_List_Member (Context)
1088 and then Present (Prev (Context))
1090 Context := Prev (Context);
1093 if Nkind (Context) = N_Pragma then
1094 Context := Parent (Context);
1098 N_Entry_Declaration |
1099 N_Protected_Type_Declaration |
1101 N_Subprogram_Declaration |
1102 N_Subprogram_Specification |
1104 N_Task_Type_Declaration =>
1105 Context := Defining_Entity (Context);
1109 Context := Parent (Context);
1113 if Nkind (Context) = N_Defining_Program_Unit_Name then
1114 Context := Defining_Identifier (Context);
1117 -- Do not return a scope without a proper location
1119 if Present (Context)
1120 and then Sloc (Context) = No_Location
1126 end Enclosing_Subprogram_Or_Library_Package;
1132 function Entity_Hash (E : Entity_Id) return Entity_Hashed_Range is
1135 Entity_Hashed_Range (E mod (Entity_Id (Entity_Hashed_Range'Last) + 1));
1138 --------------------------
1139 -- Generate_Dereference --
1140 --------------------------
1142 procedure Generate_Dereference
1144 Typ : Character := 'r')
1146 procedure Create_Heap;
1147 -- Create and decorate the special entity which denotes the heap
1153 procedure Create_Heap is
1155 Name_Len := Name_Of_Heap_Variable'Length;
1156 Name_Buffer (1 .. Name_Len) := Name_Of_Heap_Variable;
1158 Heap := Make_Defining_Identifier (Standard_Location, Name_Enter);
1160 Set_Ekind (Heap, E_Variable);
1161 Set_Is_Internal (Heap, True);
1162 Set_Has_Fully_Qualified_Name (Heap);
1167 Loc : constant Source_Ptr := Sloc (N);
1169 Ref_Scope : Entity_Id;
1171 -- Start of processing for Generate_Dereference
1175 if Loc > No_Location then
1176 Drefs.Increment_Last;
1177 Index := Drefs.Last;
1180 Deref_Entry : Xref_Entry renames Drefs.Table (Index);
1181 Deref : Xref_Key renames Deref_Entry.Key;
1188 Ref_Scope := Enclosing_Subprogram_Or_Library_Package (N);
1194 -- It is as if the special "Heap" was defined in the main unit,
1195 -- in the scope of the entity for the main unit. This single
1196 -- definition point is required to ensure that sorting cross
1197 -- references works for "Heap" references as well.
1199 Deref.Eun := Main_Unit;
1200 Deref.Lun := Get_Top_Level_Code_Unit (Loc);
1202 Deref.Ref_Scope := Ref_Scope;
1203 Deref.Ent_Scope := Cunit_Entity (Main_Unit);
1205 Deref_Entry.Def := No_Location;
1207 Deref_Entry.Ent_Scope_File := Main_Unit;
1210 end Generate_Dereference;
1212 -------------------------------
1213 -- Traverse_Compilation_Unit --
1214 -------------------------------
1216 procedure Traverse_Compilation_Unit
1218 Process : Node_Processing;
1219 Inside_Stubs : Boolean)
1224 -- Get Unit (checking case of subunit)
1228 if Nkind (Lu) = N_Subunit then
1229 Lu := Proper_Body (Lu);
1232 -- Do not add scopes for generic units
1234 if Nkind (Lu) = N_Package_Body
1235 and then Ekind (Corresponding_Spec (Lu)) in Generic_Unit_Kind
1240 -- Call Process on all declarations
1242 if Nkind (Lu) in N_Declaration
1243 or else Nkind (Lu) in N_Later_Decl_Item
1248 -- Traverse the unit
1250 Traverse_Declaration_Or_Statement (Lu, Process, Inside_Stubs);
1251 end Traverse_Compilation_Unit;
1253 ---------------------------------------
1254 -- Traverse_Declaration_Or_Statement --
1255 ---------------------------------------
1257 procedure Traverse_Declaration_Or_Statement
1259 Process : Node_Processing;
1260 Inside_Stubs : Boolean)
1264 when N_Package_Declaration =>
1266 Spec : constant Node_Id := Specification (N);
1268 Traverse_Declarations_Or_Statements
1269 (Visible_Declarations (Spec), Process, Inside_Stubs);
1270 Traverse_Declarations_Or_Statements
1271 (Private_Declarations (Spec), Process, Inside_Stubs);
1274 when N_Package_Body =>
1275 if Ekind (Defining_Entity (N)) /= E_Generic_Package then
1276 Traverse_Package_Body (N, Process, Inside_Stubs);
1279 when N_Package_Body_Stub =>
1280 if Present (Library_Unit (N)) then
1282 Body_N : constant Node_Id := Get_Body_From_Stub (N);
1286 Ekind (Defining_Entity (Body_N)) /= E_Generic_Package
1288 Traverse_Package_Body (Body_N, Process, Inside_Stubs);
1293 when N_Subprogram_Declaration =>
1296 when N_Entry_Body | N_Subprogram_Body =>
1297 if not Is_Generic_Subprogram (Defining_Entity (N)) then
1298 Traverse_Subprogram_Body (N, Process, Inside_Stubs);
1301 when N_Subprogram_Body_Stub =>
1302 if Present (Library_Unit (N)) then
1304 Body_N : constant Node_Id := Get_Body_From_Stub (N);
1308 not Is_Generic_Subprogram (Defining_Entity (Body_N))
1310 Traverse_Subprogram_Body (Body_N, Process, Inside_Stubs);
1315 when N_Protected_Body =>
1316 Traverse_Protected_Body (N, Process, Inside_Stubs);
1318 when N_Protected_Body_Stub =>
1319 if Present (Library_Unit (N)) then
1321 Body_N : constant Node_Id := Get_Body_From_Stub (N);
1323 if Inside_Stubs then
1324 Traverse_Declarations_Or_Statements
1325 (Declarations (Body_N), Process, Inside_Stubs);
1330 when N_Protected_Type_Declaration | N_Single_Protected_Declaration =>
1332 Def : constant Node_Id := Protected_Definition (N);
1334 Traverse_Declarations_Or_Statements
1335 (Visible_Declarations (Def), Process, Inside_Stubs);
1336 Traverse_Declarations_Or_Statements
1337 (Private_Declarations (Def), Process, Inside_Stubs);
1340 when N_Task_Definition =>
1341 Traverse_Declarations_Or_Statements
1342 (Visible_Declarations (N), Process, Inside_Stubs);
1343 Traverse_Declarations_Or_Statements
1344 (Private_Declarations (N), Process, Inside_Stubs);
1347 Traverse_Declarations_Or_Statements
1348 (Declarations (N), Process, Inside_Stubs);
1349 Traverse_Handled_Statement_Sequence
1350 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1352 when N_Task_Body_Stub =>
1353 if Present (Library_Unit (N)) then
1355 Body_N : constant Node_Id := Get_Body_From_Stub (N);
1357 if Inside_Stubs then
1358 Traverse_Declarations_Or_Statements
1359 (Declarations (Body_N), Process, Inside_Stubs);
1360 Traverse_Handled_Statement_Sequence
1361 (Handled_Statement_Sequence (Body_N), Process,
1367 when N_Block_Statement =>
1368 Traverse_Declarations_Or_Statements
1369 (Declarations (N), Process, Inside_Stubs);
1370 Traverse_Handled_Statement_Sequence
1371 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1373 when N_If_Statement =>
1375 -- Traverse the statements in the THEN part
1377 Traverse_Declarations_Or_Statements
1378 (Then_Statements (N), Process, Inside_Stubs);
1380 -- Loop through ELSIF parts if present
1382 if Present (Elsif_Parts (N)) then
1384 Elif : Node_Id := First (Elsif_Parts (N));
1387 while Present (Elif) loop
1388 Traverse_Declarations_Or_Statements
1389 (Then_Statements (Elif), Process, Inside_Stubs);
1395 -- Finally traverse the ELSE statements if present
1397 Traverse_Declarations_Or_Statements
1398 (Else_Statements (N), Process, Inside_Stubs);
1400 when N_Case_Statement =>
1402 -- Process case branches
1407 Alt := First (Alternatives (N));
1408 while Present (Alt) loop
1409 Traverse_Declarations_Or_Statements
1410 (Statements (Alt), Process, Inside_Stubs);
1415 when N_Extended_Return_Statement =>
1416 Traverse_Handled_Statement_Sequence
1417 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1419 when N_Loop_Statement =>
1420 Traverse_Declarations_Or_Statements
1421 (Statements (N), Process, Inside_Stubs);
1423 -- Generic declarations are ignored
1428 end Traverse_Declaration_Or_Statement;
1430 -----------------------------------------
1431 -- Traverse_Declarations_Or_Statements --
1432 -----------------------------------------
1434 procedure Traverse_Declarations_Or_Statements
1436 Process : Node_Processing;
1437 Inside_Stubs : Boolean)
1442 -- Loop through statements or declarations
1445 while Present (N) loop
1446 -- Call Process on all declarations
1448 if Nkind (N) in N_Declaration
1450 Nkind (N) in N_Later_Decl_Item
1452 Nkind (N) = N_Entry_Body
1457 Traverse_Declaration_Or_Statement (N, Process, Inside_Stubs);
1461 end Traverse_Declarations_Or_Statements;
1463 -----------------------------------------
1464 -- Traverse_Handled_Statement_Sequence --
1465 -----------------------------------------
1467 procedure Traverse_Handled_Statement_Sequence
1469 Process : Node_Processing;
1470 Inside_Stubs : Boolean)
1476 Traverse_Declarations_Or_Statements
1477 (Statements (N), Process, Inside_Stubs);
1479 if Present (Exception_Handlers (N)) then
1480 Handler := First (Exception_Handlers (N));
1481 while Present (Handler) loop
1482 Traverse_Declarations_Or_Statements
1483 (Statements (Handler), Process, Inside_Stubs);
1488 end Traverse_Handled_Statement_Sequence;
1490 ---------------------------
1491 -- Traverse_Package_Body --
1492 ---------------------------
1494 procedure Traverse_Package_Body
1496 Process : Node_Processing;
1497 Inside_Stubs : Boolean) is
1499 Traverse_Declarations_Or_Statements
1500 (Declarations (N), Process, Inside_Stubs);
1501 Traverse_Handled_Statement_Sequence
1502 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1503 end Traverse_Package_Body;
1505 -----------------------------
1506 -- Traverse_Protected_Body --
1507 -----------------------------
1509 procedure Traverse_Protected_Body
1511 Process : Node_Processing;
1512 Inside_Stubs : Boolean) is
1514 Traverse_Declarations_Or_Statements
1515 (Declarations (N), Process, Inside_Stubs);
1516 end Traverse_Protected_Body;
1518 ------------------------------
1519 -- Traverse_Subprogram_Body --
1520 ------------------------------
1522 procedure Traverse_Subprogram_Body
1524 Process : Node_Processing;
1525 Inside_Stubs : Boolean)
1528 Traverse_Declarations_Or_Statements
1529 (Declarations (N), Process, Inside_Stubs);
1530 Traverse_Handled_Statement_Sequence
1531 (Handled_Statement_Sequence (N), Process, Inside_Stubs);
1532 end Traverse_Subprogram_Body;