aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.7/gcc/ada/lib-xref-alfa.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.7/gcc/ada/lib-xref-alfa.adb')
-rw-r--r--gcc-4.7/gcc/ada/lib-xref-alfa.adb1427
1 files changed, 1427 insertions, 0 deletions
diff --git a/gcc-4.7/gcc/ada/lib-xref-alfa.adb b/gcc-4.7/gcc/ada/lib-xref-alfa.adb
new file mode 100644
index 000000000..cc0aa3ac8
--- /dev/null
+++ b/gcc-4.7/gcc/ada/lib-xref-alfa.adb
@@ -0,0 +1,1427 @@
+------------------------------------------------------------------------------
+-- --
+-- GNAT COMPILER COMPONENTS --
+-- --
+-- L I B . X R E F . A L F A --
+-- --
+-- B o d y --
+-- --
+-- Copyright (C) 2011, Free Software Foundation, Inc. --
+-- --
+-- GNAT is free software; you can redistribute it and/or modify it under --
+-- terms of the GNU General Public License as published by the Free Soft- --
+-- ware Foundation; either version 3, or (at your option) any later ver- --
+-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
+-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
+-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
+-- for more details. You should have received a copy of the GNU General --
+-- Public License distributed with GNAT; see file COPYING3. If not, go to --
+-- http://www.gnu.org/licenses for a complete copy of the license. --
+-- --
+-- GNAT was originally developed by the GNAT team at New York University. --
+-- Extensive contributions were provided by Ada Core Technologies Inc. --
+-- --
+------------------------------------------------------------------------------
+
+with Alfa; use Alfa;
+with Einfo; use Einfo;
+with Nmake; use Nmake;
+with Put_Alfa;
+
+with GNAT.HTable;
+
+separate (Lib.Xref)
+package body Alfa is
+
+ ---------------------
+ -- Local Constants --
+ ---------------------
+
+ -- Table of Alfa_Entities, True for each entity kind used in Alfa
+
+ Alfa_Entities : constant array (Entity_Kind) of Boolean :=
+ (E_Void => False,
+ E_Variable => True,
+ E_Component => False,
+ E_Constant => True,
+ E_Discriminant => False,
+
+ E_Loop_Parameter => True,
+ E_In_Parameter => True,
+ E_Out_Parameter => True,
+ E_In_Out_Parameter => True,
+ E_Generic_In_Out_Parameter => False,
+
+ E_Generic_In_Parameter => False,
+ E_Named_Integer => False,
+ E_Named_Real => False,
+ E_Enumeration_Type => False,
+ E_Enumeration_Subtype => False,
+
+ E_Signed_Integer_Type => False,
+ E_Signed_Integer_Subtype => False,
+ E_Modular_Integer_Type => False,
+ E_Modular_Integer_Subtype => False,
+ E_Ordinary_Fixed_Point_Type => False,
+
+ E_Ordinary_Fixed_Point_Subtype => False,
+ E_Decimal_Fixed_Point_Type => False,
+ E_Decimal_Fixed_Point_Subtype => False,
+ E_Floating_Point_Type => False,
+ E_Floating_Point_Subtype => False,
+
+ E_Access_Type => False,
+ E_Access_Subtype => False,
+ E_Access_Attribute_Type => False,
+ E_Allocator_Type => False,
+ E_General_Access_Type => False,
+
+ E_Access_Subprogram_Type => False,
+ E_Access_Protected_Subprogram_Type => False,
+ E_Anonymous_Access_Subprogram_Type => False,
+ E_Anonymous_Access_Protected_Subprogram_Type => False,
+ E_Anonymous_Access_Type => False,
+
+ E_Array_Type => False,
+ E_Array_Subtype => False,
+ E_String_Type => False,
+ E_String_Subtype => False,
+ E_String_Literal_Subtype => False,
+
+ E_Class_Wide_Type => False,
+ E_Class_Wide_Subtype => False,
+ E_Record_Type => False,
+ E_Record_Subtype => False,
+ E_Record_Type_With_Private => False,
+
+ E_Record_Subtype_With_Private => False,
+ E_Private_Type => False,
+ E_Private_Subtype => False,
+ E_Limited_Private_Type => False,
+ E_Limited_Private_Subtype => False,
+
+ E_Incomplete_Type => False,
+ E_Incomplete_Subtype => False,
+ E_Task_Type => False,
+ E_Task_Subtype => False,
+ E_Protected_Type => False,
+
+ E_Protected_Subtype => False,
+ E_Exception_Type => False,
+ E_Subprogram_Type => False,
+ E_Enumeration_Literal => False,
+ E_Function => True,
+
+ E_Operator => True,
+ E_Procedure => True,
+ E_Entry => False,
+ E_Entry_Family => False,
+ E_Block => False,
+
+ E_Entry_Index_Parameter => False,
+ E_Exception => False,
+ E_Generic_Function => False,
+ E_Generic_Package => False,
+ E_Generic_Procedure => False,
+
+ E_Label => False,
+ E_Loop => False,
+ E_Return_Statement => False,
+ E_Package => False,
+
+ E_Package_Body => False,
+ E_Protected_Object => False,
+ E_Protected_Body => False,
+ E_Task_Body => False,
+ E_Subprogram_Body => False);
+
+ -- True for each reference type used in Alfa
+ Alfa_References : constant array (Character) of Boolean :=
+ ('m' => True,
+ 'r' => True,
+ 's' => True,
+ others => False);
+
+ type Entity_Hashed_Range is range 0 .. 255;
+ -- Size of hash table headers
+
+ ---------------------
+ -- Local Variables --
+ ---------------------
+
+ package Drefs is new Table.Table (
+ Table_Component_Type => Xref_Entry,
+ Table_Index_Type => Xref_Entry_Number,
+ Table_Low_Bound => 1,
+ Table_Initial => Alloc.Xrefs_Initial,
+ Table_Increment => Alloc.Xrefs_Increment,
+ Table_Name => "Drefs");
+ -- Table of cross-references for reads and writes through explicit
+ -- dereferences, that are output as reads/writes to the special variable
+ -- "Heap". These references are added to the regular references when
+ -- computing Alfa cross-references.
+
+ -----------------------
+ -- Local Subprograms --
+ -----------------------
+
+ procedure Add_Alfa_File (U : Unit_Number_Type; D : Nat);
+ -- Add file U and all scopes in U to the tables Alfa_File_Table and
+ -- Alfa_Scope_Table.
+
+ procedure Add_Alfa_Scope (N : Node_Id);
+ -- Add scope N to the table Alfa_Scope_Table
+
+ procedure Add_Alfa_Xrefs;
+ -- Filter table Xrefs to add all references used in Alfa to the table
+ -- Alfa_Xref_Table.
+
+ procedure Detect_And_Add_Alfa_Scope (N : Node_Id);
+ -- Call Add_Alfa_Scope on scopes
+
+ function Entity_Hash (E : Entity_Id) return Entity_Hashed_Range;
+ -- Hash function for hash table
+
+ procedure Traverse_Declarations_Or_Statements
+ (L : List_Id;
+ Process : Node_Processing;
+ Inside_Stubs : Boolean);
+ procedure Traverse_Handled_Statement_Sequence
+ (N : Node_Id;
+ Process : Node_Processing;
+ Inside_Stubs : Boolean);
+ procedure Traverse_Package_Body
+ (N : Node_Id;
+ Process : Node_Processing;
+ Inside_Stubs : Boolean);
+ procedure Traverse_Package_Declaration
+ (N : Node_Id;
+ Process : Node_Processing;
+ Inside_Stubs : Boolean);
+ procedure Traverse_Subprogram_Body
+ (N : Node_Id;
+ Process : Node_Processing;
+ Inside_Stubs : Boolean);
+ -- Traverse the corresponding constructs, calling Process on all
+ -- declarations.
+
+ -------------------
+ -- Add_Alfa_File --
+ -------------------
+
+ procedure Add_Alfa_File (U : Unit_Number_Type; D : Nat) is
+ From : Scope_Index;
+
+ S : constant Source_File_Index := Source_Index (U);
+
+ begin
+ -- Source file could be inexistant as a result of an error, if option
+ -- gnatQ is used.
+
+ if S = No_Source_File then
+ return;
+ end if;
+
+ From := Alfa_Scope_Table.Last + 1;
+
+ Traverse_Compilation_Unit (Cunit (U), Detect_And_Add_Alfa_Scope'Access,
+ Inside_Stubs => False);
+
+ -- Update scope numbers
+
+ declare
+ Count : Nat;
+
+ begin
+ Count := 1;
+ for S in From .. Alfa_Scope_Table.Last loop
+ declare
+ E : Entity_Id renames Alfa_Scope_Table.Table (S).Scope_Entity;
+
+ begin
+ if Lib.Get_Source_Unit (E) = U then
+ Alfa_Scope_Table.Table (S).Scope_Num := Count;
+ Alfa_Scope_Table.Table (S).File_Num := D;
+ Count := Count + 1;
+
+ else
+ -- Mark for removal a scope S which is not located in unit
+ -- U, for example for scope inside generics that get
+ -- instantiated.
+
+ Alfa_Scope_Table.Table (S).Scope_Num := 0;
+ end if;
+ end;
+ end loop;
+ end;
+
+ declare
+ Snew : Scope_Index;
+
+ begin
+ Snew := From;
+ for S in From .. Alfa_Scope_Table.Last loop
+ -- Remove those scopes previously marked for removal
+
+ if Alfa_Scope_Table.Table (S).Scope_Num /= 0 then
+ Alfa_Scope_Table.Table (Snew) := Alfa_Scope_Table.Table (S);
+ Snew := Snew + 1;
+ end if;
+ end loop;
+
+ Alfa_Scope_Table.Set_Last (Snew - 1);
+ end;
+
+ -- Make entry for new file in file table
+
+ Get_Name_String (Reference_Name (S));
+
+ Alfa_File_Table.Append (
+ (File_Name => new String'(Name_Buffer (1 .. Name_Len)),
+ File_Num => D,
+ From_Scope => From,
+ To_Scope => Alfa_Scope_Table.Last));
+ end Add_Alfa_File;
+
+ --------------------
+ -- Add_Alfa_Scope --
+ --------------------
+
+ procedure Add_Alfa_Scope (N : Node_Id) is
+ E : constant Entity_Id := Defining_Entity (N);
+ Loc : constant Source_Ptr := Sloc (E);
+ Typ : Character;
+
+ begin
+ -- Ignore scopes without a proper location
+
+ if Sloc (N) = No_Location then
+ return;
+ end if;
+
+ case Ekind (E) is
+ when E_Function | E_Generic_Function =>
+ Typ := 'V';
+
+ when E_Procedure | E_Generic_Procedure =>
+ Typ := 'U';
+
+ when E_Subprogram_Body =>
+ declare
+ Spec : Node_Id;
+
+ begin
+ Spec := Parent (E);
+
+ if Nkind (Spec) = N_Defining_Program_Unit_Name then
+ Spec := Parent (Spec);
+ end if;
+
+ if Nkind (Spec) = N_Function_Specification then
+ Typ := 'V';
+ else
+ pragma Assert
+ (Nkind (Spec) = N_Procedure_Specification);
+ Typ := 'U';
+ end if;
+ end;
+
+ when E_Package | E_Package_Body | E_Generic_Package =>
+ Typ := 'K';
+
+ when E_Void =>
+ -- Compilation of prj-attr.adb with -gnatn creates a node with
+ -- entity E_Void for the package defined at a-charac.ads16:13
+
+ -- ??? TBD
+
+ return;
+
+ when others =>
+ raise Program_Error;
+ end case;
+
+ -- File_Num and Scope_Num are filled later. From_Xref and To_Xref are
+ -- filled even later, but are initialized to represent an empty range.
+
+ Alfa_Scope_Table.Append (
+ (Scope_Name => new String'(Unique_Name (E)),
+ File_Num => 0,
+ Scope_Num => 0,
+ Spec_File_Num => 0,
+ Spec_Scope_Num => 0,
+ Line => Nat (Get_Logical_Line_Number (Loc)),
+ Stype => Typ,
+ Col => Nat (Get_Column_Number (Loc)),
+ From_Xref => 1,
+ To_Xref => 0,
+ Scope_Entity => E));
+ end Add_Alfa_Scope;
+
+ --------------------
+ -- Add_Alfa_Xrefs --
+ --------------------
+
+ procedure Add_Alfa_Xrefs is
+ Cur_Scope_Idx : Scope_Index;
+ From_Xref_Idx : Xref_Index;
+ Cur_Entity : Entity_Id;
+ Cur_Entity_Name : String_Ptr;
+
+ package Scopes is
+ No_Scope : constant Nat := 0;
+ function Get_Scope_Num (N : Entity_Id) return Nat;
+ procedure Set_Scope_Num (N : Entity_Id; Num : Nat);
+ end Scopes;
+
+ ------------
+ -- Scopes --
+ ------------
+
+ package body Scopes is
+ type Scope is record
+ Num : Nat;
+ Entity : Entity_Id;
+ end record;
+
+ package Scopes is new GNAT.HTable.Simple_HTable
+ (Header_Num => Entity_Hashed_Range,
+ Element => Scope,
+ No_Element => (Num => No_Scope, Entity => Empty),
+ Key => Entity_Id,
+ Hash => Entity_Hash,
+ Equal => "=");
+
+ -------------------
+ -- Get_Scope_Num --
+ -------------------
+
+ function Get_Scope_Num (N : Entity_Id) return Nat is
+ begin
+ return Scopes.Get (N).Num;
+ end Get_Scope_Num;
+
+ -------------------
+ -- Set_Scope_Num --
+ -------------------
+
+ procedure Set_Scope_Num (N : Entity_Id; Num : Nat) is
+ begin
+ Scopes.Set (K => N, E => Scope'(Num => Num, Entity => N));
+ end Set_Scope_Num;
+ end Scopes;
+
+ use Scopes;
+
+ Nrefs : Nat := Xrefs.Last;
+ -- Number of references in table. This value may get reset (reduced)
+ -- when we eliminate duplicate reference entries as well as references
+ -- not suitable for local cross-references.
+
+ Nrefs_Add : constant Nat := Drefs.Last;
+
+ Rnums : array (0 .. Nrefs + Nrefs_Add) of Nat;
+ -- This array contains numbers of references in the Xrefs table. This
+ -- list is sorted in output order. The extra 0'th entry is convenient
+ -- for the call to sort. When we sort the table, we move the entries in
+ -- Rnums around, but we do not move the original table entries.
+
+ function Lt (Op1, Op2 : Natural) return Boolean;
+ -- Comparison function for Sort call
+
+ procedure Move (From : Natural; To : Natural);
+ -- Move procedure for Sort call
+
+ package Sorting is new GNAT.Heap_Sort_G (Move, Lt);
+
+ --------
+ -- Lt --
+ --------
+
+ function Lt (Op1, Op2 : Natural) return Boolean is
+ T1 : constant Xref_Entry := Xrefs.Table (Rnums (Nat (Op1)));
+ T2 : constant Xref_Entry := Xrefs.Table (Rnums (Nat (Op2)));
+
+ begin
+ -- First test: if entity is in different unit, sort by unit. Note:
+ -- that we use Ent_Scope_File rather than Eun, as Eun may refer to
+ -- the file where the generic scope is defined, which may differ from
+ -- the file where the enclosing scope is defined. It is the latter
+ -- which matters for a correct order here.
+
+ if T1.Ent_Scope_File /= T2.Ent_Scope_File then
+ return Dependency_Num (T1.Ent_Scope_File) <
+ Dependency_Num (T2.Ent_Scope_File);
+
+ -- Second test: within same unit, sort by location of the scope of
+ -- the entity definition.
+
+ elsif Get_Scope_Num (T1.Key.Ent_Scope) /=
+ Get_Scope_Num (T2.Key.Ent_Scope)
+ then
+ return Get_Scope_Num (T1.Key.Ent_Scope) <
+ Get_Scope_Num (T2.Key.Ent_Scope);
+
+ -- Third test: within same unit and scope, sort by location of
+ -- entity definition.
+
+ elsif T1.Def /= T2.Def then
+ return T1.Def < T2.Def;
+
+ -- Fourth test: if reference is in same unit as entity definition,
+ -- sort first.
+
+ elsif
+ T1.Key.Lun /= T2.Key.Lun and then T1.Ent_Scope_File = T1.Key.Lun
+ then
+ return True;
+
+ elsif
+ T1.Key.Lun /= T2.Key.Lun and then T2.Ent_Scope_File = T2.Key.Lun
+ then
+ return False;
+
+ -- Fifth test: if reference is in same unit and same scope as entity
+ -- definition, sort first.
+
+ elsif T1.Ent_Scope_File = T1.Key.Lun
+ and then T1.Key.Ref_Scope /= T2.Key.Ref_Scope
+ and then T1.Key.Ent_Scope = T1.Key.Ref_Scope
+ then
+ return True;
+ elsif T1.Ent_Scope_File = T1.Key.Lun
+ and then T1.Key.Ref_Scope /= T2.Key.Ref_Scope
+ and then T2.Key.Ent_Scope = T2.Key.Ref_Scope
+ then
+ return False;
+
+ -- Sixth test: for same entity, sort by reference location unit
+
+ elsif T1.Key.Lun /= T2.Key.Lun then
+ return Dependency_Num (T1.Key.Lun) < Dependency_Num (T2.Key.Lun);
+
+ -- Seventh test: for same entity, sort by reference location scope
+
+ elsif Get_Scope_Num (T1.Key.Ref_Scope) /=
+ Get_Scope_Num (T2.Key.Ref_Scope)
+ then
+ return Get_Scope_Num (T1.Key.Ref_Scope) <
+ Get_Scope_Num (T2.Key.Ref_Scope);
+
+ -- Eighth test: order of location within referencing unit
+
+ elsif T1.Key.Loc /= T2.Key.Loc then
+ return T1.Key.Loc < T2.Key.Loc;
+
+ -- Finally, for two locations at the same address prefer the one that
+ -- does NOT have the type 'r', so that a modification or extension
+ -- takes preference, when there are more than one reference at the
+ -- same location. As a result, in the case of entities that are
+ -- in-out actuals, the read reference follows the modify reference.
+
+ else
+ return T2.Key.Typ = 'r';
+ end if;
+ end Lt;
+
+ ----------
+ -- Move --
+ ----------
+
+ procedure Move (From : Natural; To : Natural) is
+ begin
+ Rnums (Nat (To)) := Rnums (Nat (From));
+ end Move;
+
+ Heap : Entity_Id;
+
+ -- Start of processing for Add_Alfa_Xrefs
+
+ begin
+ for J in Alfa_Scope_Table.First .. Alfa_Scope_Table.Last loop
+ Set_Scope_Num (N => Alfa_Scope_Table.Table (J).Scope_Entity,
+ Num => Alfa_Scope_Table.Table (J).Scope_Num);
+ end loop;
+
+ -- Set up the pointer vector for the sort
+
+ for J in 1 .. Nrefs loop
+ Rnums (J) := J;
+ end loop;
+
+ -- Add dereferences to the set of regular references, by creating a
+ -- special "Heap" variable for these special references.
+
+ Name_Len := Name_Of_Heap_Variable'Length;
+ Name_Buffer (1 .. Name_Len) := Name_Of_Heap_Variable;
+
+ Atree.Unlock;
+ Nlists.Unlock;
+ Heap := Make_Defining_Identifier (Standard_Location, Name_Enter);
+ Atree.Lock;
+ Nlists.Lock;
+
+ Set_Ekind (Heap, E_Variable);
+ Set_Is_Internal (Heap, True);
+ Set_Has_Fully_Qualified_Name (Heap);
+
+ for J in Drefs.First .. Drefs.Last loop
+ Xrefs.Append (Drefs.Table (J));
+
+ -- Set entity at this point with newly created "Heap" variable
+
+ Xrefs.Table (Xrefs.Last).Key.Ent := Heap;
+
+ Nrefs := Nrefs + 1;
+ Rnums (Nrefs) := Xrefs.Last;
+ end loop;
+
+ -- Eliminate entries not appropriate for Alfa. Done prior to sorting
+ -- cross-references, as it discards useless references which do not have
+ -- a proper format for the comparison function (like no location).
+
+ Eliminate_Before_Sort : declare
+ NR : Nat;
+
+ function Is_Alfa_Reference
+ (E : Entity_Id;
+ Typ : Character) return Boolean;
+ -- Return whether entity reference E meets Alfa requirements. Typ
+ -- is the reference type.
+
+ function Is_Alfa_Scope (E : Entity_Id) return Boolean;
+ -- Return whether the entity or reference scope meets requirements
+ -- for being an Alfa scope.
+
+ function Is_Global_Constant (E : Entity_Id) return Boolean;
+ -- Return True if E is a global constant for which we should ignore
+ -- reads in Alfa.
+
+ -----------------------
+ -- Is_Alfa_Reference --
+ -----------------------
+
+ function Is_Alfa_Reference
+ (E : Entity_Id;
+ Typ : Character) return Boolean
+ is
+ begin
+ -- The only references of interest on callable entities are calls.
+ -- On non-callable entities, the only references of interest are
+ -- reads and writes.
+
+ if Ekind (E) in Overloadable_Kind then
+ return Typ = 's';
+
+ -- References to constant objects are not considered in Alfa
+ -- section, as these will be translated as constants in the
+ -- intermediate language for formal verification, and should
+ -- therefore never appear in frame conditions.
+
+ elsif Is_Constant_Object (E) then
+ return False;
+
+ -- Objects of Task type or protected type are not Alfa references
+
+ elsif Present (Etype (E))
+ and then Ekind (Etype (E)) in Concurrent_Kind
+ then
+ return False;
+
+ -- In all other cases, result is true for reference/modify cases,
+ -- and false for all other cases.
+
+ else
+ return Typ = 'r' or else Typ = 'm';
+ end if;
+ end Is_Alfa_Reference;
+
+ -------------------
+ -- Is_Alfa_Scope --
+ -------------------
+
+ function Is_Alfa_Scope (E : Entity_Id) return Boolean is
+ begin
+ return Present (E)
+ and then not Is_Generic_Unit (E)
+ and then Renamed_Entity (E) = Empty
+ and then Get_Scope_Num (E) /= No_Scope;
+ end Is_Alfa_Scope;
+
+ ------------------------
+ -- Is_Global_Constant --
+ ------------------------
+
+ function Is_Global_Constant (E : Entity_Id) return Boolean is
+ begin
+ return Ekind (E) = E_Constant
+ and then Ekind_In (Scope (E), E_Package, E_Package_Body);
+ end Is_Global_Constant;
+
+ -- Start of processing for Eliminate_Before_Sort
+
+ begin
+ NR := Nrefs;
+ Nrefs := 0;
+
+ for J in 1 .. NR loop
+ if Alfa_Entities (Ekind (Xrefs.Table (Rnums (J)).Key.Ent))
+ and then Alfa_References (Xrefs.Table (Rnums (J)).Key.Typ)
+ and then Is_Alfa_Scope (Xrefs.Table (Rnums (J)).Key.Ent_Scope)
+ and then Is_Alfa_Scope (Xrefs.Table (Rnums (J)).Key.Ref_Scope)
+ and then not Is_Global_Constant (Xrefs.Table (Rnums (J)).Key.Ent)
+ and then Is_Alfa_Reference (Xrefs.Table (Rnums (J)).Key.Ent,
+ Xrefs.Table (Rnums (J)).Key.Typ)
+ then
+ Nrefs := Nrefs + 1;
+ Rnums (Nrefs) := Rnums (J);
+ end if;
+ end loop;
+ end Eliminate_Before_Sort;
+
+ -- Sort the references
+
+ Sorting.Sort (Integer (Nrefs));
+
+ Eliminate_After_Sort : declare
+ NR : Nat;
+
+ Crloc : Source_Ptr;
+ -- Current reference location
+
+ Prevt : Character;
+ -- reference kind of previous reference
+
+ begin
+ -- Eliminate duplicate entries
+
+ -- We need this test for NR because if we force ALI file generation
+ -- in case of errors detected, it may be the case that Nrefs is 0, so
+ -- we should not reset it here
+
+ if Nrefs >= 2 then
+ NR := Nrefs;
+ Nrefs := 1;
+
+ for J in 2 .. NR loop
+ if Xrefs.Table (Rnums (J)) /=
+ Xrefs.Table (Rnums (Nrefs))
+ then
+ Nrefs := Nrefs + 1;
+ Rnums (Nrefs) := Rnums (J);
+ end if;
+ end loop;
+ end if;
+
+ -- Eliminate the reference if it is at the same location as the
+ -- previous one, unless it is a read-reference indicating that the
+ -- entity is an in-out actual in a call.
+
+ NR := Nrefs;
+ Nrefs := 0;
+ Crloc := No_Location;
+ Prevt := 'm';
+
+ for J in 1 .. NR loop
+ if Xrefs.Table (Rnums (J)).Key.Loc /= Crloc
+ or else (Prevt = 'm'
+ and then Xrefs.Table (Rnums (J)).Key.Typ = 'r')
+ then
+ Crloc := Xrefs.Table (Rnums (J)).Key.Loc;
+ Prevt := Xrefs.Table (Rnums (J)).Key.Typ;
+ Nrefs := Nrefs + 1;
+ Rnums (Nrefs) := Rnums (J);
+ end if;
+ end loop;
+ end Eliminate_After_Sort;
+
+ -- Initialize loop
+
+ Cur_Scope_Idx := 1;
+ From_Xref_Idx := 1;
+ Cur_Entity := Empty;
+
+ if Alfa_Scope_Table.Last = 0 then
+ return;
+ end if;
+
+ -- Loop to output references
+
+ for Refno in 1 .. Nrefs loop
+ Add_One_Xref : declare
+
+ -----------------------
+ -- Local Subprograms --
+ -----------------------
+
+ function Cur_Scope return Node_Id;
+ -- Return scope entity which corresponds to index Cur_Scope_Idx in
+ -- table Alfa_Scope_Table.
+
+ function Get_Entity_Type (E : Entity_Id) return Character;
+ -- Return a character representing the type of entity
+
+ function Is_Future_Scope_Entity (E : Entity_Id) return Boolean;
+ -- Check whether entity E is in Alfa_Scope_Table at index
+ -- Cur_Scope_Idx or higher.
+
+ function Is_Past_Scope_Entity (E : Entity_Id) return Boolean;
+ -- Check whether entity E is in Alfa_Scope_Table at index strictly
+ -- lower than Cur_Scope_Idx.
+
+ ---------------
+ -- Cur_Scope --
+ ---------------
+
+ function Cur_Scope return Node_Id is
+ begin
+ return Alfa_Scope_Table.Table (Cur_Scope_Idx).Scope_Entity;
+ end Cur_Scope;
+
+ ---------------------
+ -- Get_Entity_Type --
+ ---------------------
+
+ function Get_Entity_Type (E : Entity_Id) return Character is
+ C : Character;
+ begin
+ case Ekind (E) is
+ when E_Out_Parameter => C := '<';
+ when E_In_Out_Parameter => C := '=';
+ when E_In_Parameter => C := '>';
+ when others => C := '*';
+ end case;
+ return C;
+ end Get_Entity_Type;
+
+ ----------------------------
+ -- Is_Future_Scope_Entity --
+ ----------------------------
+
+ function Is_Future_Scope_Entity (E : Entity_Id) return Boolean is
+ begin
+ for J in Cur_Scope_Idx .. Alfa_Scope_Table.Last loop
+ if E = Alfa_Scope_Table.Table (J).Scope_Entity then
+ return True;
+ end if;
+ end loop;
+
+ -- If this assertion fails, this means that the scope which we
+ -- are looking for has been treated already, which reveals a
+ -- problem in the order of cross-references.
+
+ pragma Assert (not Is_Past_Scope_Entity (E));
+
+ return False;
+ end Is_Future_Scope_Entity;
+
+ --------------------------
+ -- Is_Past_Scope_Entity --
+ --------------------------
+
+ function Is_Past_Scope_Entity (E : Entity_Id) return Boolean is
+ begin
+ for J in Alfa_Scope_Table.First .. Cur_Scope_Idx - 1 loop
+ if E = Alfa_Scope_Table.Table (J).Scope_Entity then
+ return True;
+ end if;
+ end loop;
+
+ return False;
+ end Is_Past_Scope_Entity;
+
+ ---------------------
+ -- Local Variables --
+ ---------------------
+
+ XE : Xref_Entry renames Xrefs.Table (Rnums (Refno));
+
+ begin
+ -- If this assertion fails, the scope which we are looking for is
+ -- not in Alfa scope table, which reveals either a problem in the
+ -- construction of the scope table, or an erroneous scope for the
+ -- current cross-reference.
+
+ pragma Assert (Is_Future_Scope_Entity (XE.Key.Ent_Scope));
+
+ -- Update the range of cross references to which the current scope
+ -- refers to. This may be the empty range only for the first scope
+ -- considered.
+
+ if XE.Key.Ent_Scope /= Cur_Scope then
+ Alfa_Scope_Table.Table (Cur_Scope_Idx).From_Xref :=
+ From_Xref_Idx;
+ Alfa_Scope_Table.Table (Cur_Scope_Idx).To_Xref :=
+ Alfa_Xref_Table.Last;
+ From_Xref_Idx := Alfa_Xref_Table.Last + 1;
+ end if;
+
+ while XE.Key.Ent_Scope /= Cur_Scope loop
+ Cur_Scope_Idx := Cur_Scope_Idx + 1;
+ pragma Assert (Cur_Scope_Idx <= Alfa_Scope_Table.Last);
+ end loop;
+
+ if XE.Key.Ent /= Cur_Entity then
+ Cur_Entity_Name :=
+ new String'(Unique_Name (XE.Key.Ent));
+ end if;
+
+ if XE.Key.Ent = Heap then
+ Alfa_Xref_Table.Append (
+ (Entity_Name => Cur_Entity_Name,
+ Entity_Line => 0,
+ Etype => Get_Entity_Type (XE.Key.Ent),
+ Entity_Col => 0,
+ File_Num => Dependency_Num (XE.Key.Lun),
+ Scope_Num => Get_Scope_Num (XE.Key.Ref_Scope),
+ Line => Int (Get_Logical_Line_Number (XE.Key.Loc)),
+ Rtype => XE.Key.Typ,
+ Col => Int (Get_Column_Number (XE.Key.Loc))));
+
+ else
+ Alfa_Xref_Table.Append (
+ (Entity_Name => Cur_Entity_Name,
+ Entity_Line => Int (Get_Logical_Line_Number (XE.Def)),
+ Etype => Get_Entity_Type (XE.Key.Ent),
+ Entity_Col => Int (Get_Column_Number (XE.Def)),
+ File_Num => Dependency_Num (XE.Key.Lun),
+ Scope_Num => Get_Scope_Num (XE.Key.Ref_Scope),
+ Line => Int (Get_Logical_Line_Number (XE.Key.Loc)),
+ Rtype => XE.Key.Typ,
+ Col => Int (Get_Column_Number (XE.Key.Loc))));
+ end if;
+ end Add_One_Xref;
+ end loop;
+
+ -- Update the range of cross references to which the scope refers to
+
+ Alfa_Scope_Table.Table (Cur_Scope_Idx).From_Xref := From_Xref_Idx;
+ Alfa_Scope_Table.Table (Cur_Scope_Idx).To_Xref := Alfa_Xref_Table.Last;
+ end Add_Alfa_Xrefs;
+
+ ------------------
+ -- Collect_Alfa --
+ ------------------
+
+ procedure Collect_Alfa (Sdep_Table : Unit_Ref_Table; Num_Sdep : Nat) is
+ begin
+ -- Cross-references should have been computed first
+
+ pragma Assert (Xrefs.Last /= 0);
+
+ Initialize_Alfa_Tables;
+
+ -- Generate file and scope Alfa information
+
+ for D in 1 .. Num_Sdep loop
+ Add_Alfa_File (U => Sdep_Table (D), D => D);
+ end loop;
+
+ -- Fill in the spec information when relevant
+
+ declare
+ package Entity_Hash_Table is new
+ GNAT.HTable.Simple_HTable
+ (Header_Num => Entity_Hashed_Range,
+ Element => Scope_Index,
+ No_Element => 0,
+ Key => Entity_Id,
+ Hash => Entity_Hash,
+ Equal => "=");
+
+ begin
+ -- Fill in the hash-table
+
+ for S in Alfa_Scope_Table.First .. Alfa_Scope_Table.Last loop
+ declare
+ Srec : Alfa_Scope_Record renames Alfa_Scope_Table.Table (S);
+ begin
+ Entity_Hash_Table.Set (Srec.Scope_Entity, S);
+ end;
+ end loop;
+
+ -- Use the hash-table to locate spec entities
+
+ for S in Alfa_Scope_Table.First .. Alfa_Scope_Table.Last loop
+ declare
+ Srec : Alfa_Scope_Record renames Alfa_Scope_Table.Table (S);
+
+ Spec_Entity : constant Entity_Id :=
+ Unique_Entity (Srec.Scope_Entity);
+ Spec_Scope : constant Scope_Index :=
+ Entity_Hash_Table.Get (Spec_Entity);
+
+ begin
+ -- Spec of generic may be missing, in which case Spec_Scope is
+ -- zero.
+
+ if Spec_Entity /= Srec.Scope_Entity
+ and then Spec_Scope /= 0
+ then
+ Srec.Spec_File_Num :=
+ Alfa_Scope_Table.Table (Spec_Scope).File_Num;
+ Srec.Spec_Scope_Num :=
+ Alfa_Scope_Table.Table (Spec_Scope).Scope_Num;
+ end if;
+ end;
+ end loop;
+ end;
+
+ -- Generate cross reference Alfa information
+
+ Add_Alfa_Xrefs;
+ end Collect_Alfa;
+
+ -------------------------------
+ -- Detect_And_Add_Alfa_Scope --
+ -------------------------------
+
+ procedure Detect_And_Add_Alfa_Scope (N : Node_Id) is
+ begin
+ if Nkind_In (N, N_Subprogram_Declaration,
+ N_Subprogram_Body,
+ N_Subprogram_Body_Stub,
+ N_Package_Declaration,
+ N_Package_Body)
+ then
+ Add_Alfa_Scope (N);
+ end if;
+ end Detect_And_Add_Alfa_Scope;
+
+ -------------------------------------
+ -- Enclosing_Subprogram_Or_Package --
+ -------------------------------------
+
+ function Enclosing_Subprogram_Or_Package (N : Node_Id) return Entity_Id is
+ Result : Entity_Id;
+
+ begin
+ -- If N is the defining identifier for a subprogram, then return the
+ -- enclosing subprogram or package, not this subprogram.
+
+ if Nkind_In (N, N_Defining_Identifier, N_Defining_Operator_Symbol)
+ and then Nkind (Parent (N)) in N_Subprogram_Specification
+ then
+ Result := Parent (Parent (Parent (N)));
+ else
+ Result := N;
+ end if;
+
+ loop
+ exit when No (Result);
+
+ case Nkind (Result) is
+ when N_Package_Specification =>
+ Result := Defining_Unit_Name (Result);
+ exit;
+
+ when N_Package_Body =>
+ Result := Defining_Unit_Name (Result);
+ exit;
+
+ when N_Subprogram_Specification =>
+ Result := Defining_Unit_Name (Result);
+ exit;
+
+ when N_Subprogram_Declaration =>
+ Result := Defining_Unit_Name (Specification (Result));
+ exit;
+
+ when N_Subprogram_Body =>
+ Result := Defining_Unit_Name (Specification (Result));
+ exit;
+
+ -- The enclosing subprogram for a pre- or postconditions should be
+ -- the subprogram to which the pragma is attached. This is not
+ -- always the case in the AST, as the pragma may be declared after
+ -- the declaration of the subprogram. Return Empty in this case.
+
+ when N_Pragma =>
+ if Get_Pragma_Id (Result) = Pragma_Precondition
+ or else
+ Get_Pragma_Id (Result) = Pragma_Postcondition
+ then
+ return Empty;
+ else
+ Result := Parent (Result);
+ end if;
+
+ when others =>
+ Result := Parent (Result);
+ end case;
+ end loop;
+
+ if Nkind (Result) = N_Defining_Program_Unit_Name then
+ Result := Defining_Identifier (Result);
+ end if;
+
+ -- Do no return a scope without a proper location
+
+ if Present (Result)
+ and then Sloc (Result) = No_Location
+ then
+ return Empty;
+ end if;
+
+ return Result;
+ end Enclosing_Subprogram_Or_Package;
+
+ -----------------
+ -- Entity_Hash --
+ -----------------
+
+ function Entity_Hash (E : Entity_Id) return Entity_Hashed_Range is
+ begin
+ return
+ Entity_Hashed_Range (E mod (Entity_Id (Entity_Hashed_Range'Last) + 1));
+ end Entity_Hash;
+
+ --------------------------
+ -- Generate_Dereference --
+ --------------------------
+
+ procedure Generate_Dereference
+ (N : Node_Id;
+ Typ : Character := 'r')
+ is
+ Indx : Nat;
+ Ref : Source_Ptr;
+ Ref_Scope : Entity_Id;
+
+ begin
+ Ref := Original_Location (Sloc (N));
+
+ if Ref > No_Location then
+ Drefs.Increment_Last;
+ Indx := Drefs.Last;
+
+ Ref_Scope := Enclosing_Subprogram_Or_Package (N);
+
+ -- Entity is filled later on with the special "Heap" variable
+
+ Drefs.Table (Indx).Key.Ent := Empty;
+
+ Drefs.Table (Indx).Def := No_Location;
+ Drefs.Table (Indx).Key.Loc := Ref;
+ Drefs.Table (Indx).Key.Typ := Typ;
+
+ -- It is as if the special "Heap" was defined in every scope where it
+ -- is referenced.
+
+ Drefs.Table (Indx).Key.Eun := Get_Source_Unit (Ref);
+ Drefs.Table (Indx).Key.Lun := Get_Source_Unit (Ref);
+
+ Drefs.Table (Indx).Key.Ref_Scope := Ref_Scope;
+ Drefs.Table (Indx).Key.Ent_Scope := Ref_Scope;
+ Drefs.Table (Indx).Ent_Scope_File := Get_Source_Unit (Ref_Scope);
+ end if;
+ end Generate_Dereference;
+
+ ------------------------------------
+ -- Traverse_All_Compilation_Units --
+ ------------------------------------
+
+ procedure Traverse_All_Compilation_Units (Process : Node_Processing) is
+ begin
+ for U in Units.First .. Last_Unit loop
+ Traverse_Compilation_Unit (Cunit (U), Process, Inside_Stubs => False);
+ end loop;
+ end Traverse_All_Compilation_Units;
+
+ -------------------------------
+ -- Traverse_Compilation_Unit --
+ -------------------------------
+
+ procedure Traverse_Compilation_Unit
+ (CU : Node_Id;
+ Process : Node_Processing;
+ Inside_Stubs : Boolean)
+ is
+ Lu : Node_Id;
+
+ begin
+ -- Get Unit (checking case of subunit)
+
+ Lu := Unit (CU);
+
+ if Nkind (Lu) = N_Subunit then
+ Lu := Proper_Body (Lu);
+ end if;
+
+ -- Call Process on all declarations
+
+ if Nkind (Lu) in N_Declaration
+ or else Nkind (Lu) in N_Later_Decl_Item
+ then
+ Process (Lu);
+ end if;
+
+ -- Traverse the unit
+
+ if Nkind (Lu) = N_Subprogram_Body then
+ Traverse_Subprogram_Body (Lu, Process, Inside_Stubs);
+
+ elsif Nkind (Lu) = N_Subprogram_Declaration then
+ null;
+
+ elsif Nkind (Lu) = N_Package_Declaration then
+ Traverse_Package_Declaration (Lu, Process, Inside_Stubs);
+
+ elsif Nkind (Lu) = N_Package_Body then
+ Traverse_Package_Body (Lu, Process, Inside_Stubs);
+
+ -- ??? TBD
+
+ elsif Nkind (Lu) = N_Generic_Package_Declaration then
+ null;
+
+ -- ??? TBD
+
+ elsif Nkind (Lu) in N_Generic_Instantiation then
+ null;
+
+ -- All other cases of compilation units (e.g. renamings), are not
+ -- declarations.
+
+ else
+ null;
+ end if;
+ end Traverse_Compilation_Unit;
+
+ -----------------------------------------
+ -- Traverse_Declarations_Or_Statements --
+ -----------------------------------------
+
+ procedure Traverse_Declarations_Or_Statements
+ (L : List_Id;
+ Process : Node_Processing;
+ Inside_Stubs : Boolean)
+ is
+ N : Node_Id;
+
+ begin
+ -- Loop through statements or declarations
+
+ N := First (L);
+ while Present (N) loop
+ -- Call Process on all declarations
+
+ if Nkind (N) in N_Declaration
+ or else
+ Nkind (N) in N_Later_Decl_Item
+ then
+ Process (N);
+ end if;
+
+ case Nkind (N) is
+
+ -- Package declaration
+
+ when N_Package_Declaration =>
+ Traverse_Package_Declaration (N, Process, Inside_Stubs);
+
+ -- Generic package declaration ??? TBD
+
+ when N_Generic_Package_Declaration =>
+ null;
+
+ -- Package body
+
+ when N_Package_Body =>
+ if Ekind (Defining_Entity (N)) /= E_Generic_Package then
+ Traverse_Package_Body (N, Process, Inside_Stubs);
+ end if;
+
+ when N_Package_Body_Stub =>
+ if Present (Library_Unit (N)) then
+ declare
+ Body_N : constant Node_Id := Get_Body_From_Stub (N);
+ begin
+ if Inside_Stubs
+ and then
+ Ekind (Defining_Entity (Body_N)) /= E_Generic_Package
+ then
+ Traverse_Package_Body (Body_N, Process, Inside_Stubs);
+ end if;
+ end;
+ end if;
+
+ -- Subprogram declaration
+
+ when N_Subprogram_Declaration =>
+ null;
+
+ -- Generic subprogram declaration ??? TBD
+
+ when N_Generic_Subprogram_Declaration =>
+ null;
+
+ -- Subprogram body
+
+ when N_Subprogram_Body =>
+ if not Is_Generic_Subprogram (Defining_Entity (N)) then
+ Traverse_Subprogram_Body (N, Process, Inside_Stubs);
+ end if;
+
+ when N_Subprogram_Body_Stub =>
+ if Present (Library_Unit (N)) then
+ declare
+ Body_N : constant Node_Id := Get_Body_From_Stub (N);
+ begin
+ if Inside_Stubs
+ and then
+ not Is_Generic_Subprogram (Defining_Entity (Body_N))
+ then
+ Traverse_Subprogram_Body
+ (Body_N, Process, Inside_Stubs);
+ end if;
+ end;
+ end if;
+
+ -- Block statement
+
+ when N_Block_Statement =>
+ Traverse_Declarations_Or_Statements
+ (Declarations (N), Process, Inside_Stubs);
+ Traverse_Handled_Statement_Sequence
+ (Handled_Statement_Sequence (N), Process, Inside_Stubs);
+
+ when N_If_Statement =>
+
+ -- Traverse the statements in the THEN part
+
+ Traverse_Declarations_Or_Statements
+ (Then_Statements (N), Process, Inside_Stubs);
+
+ -- Loop through ELSIF parts if present
+
+ if Present (Elsif_Parts (N)) then
+ declare
+ Elif : Node_Id := First (Elsif_Parts (N));
+
+ begin
+ while Present (Elif) loop
+ Traverse_Declarations_Or_Statements
+ (Then_Statements (Elif), Process, Inside_Stubs);
+ Next (Elif);
+ end loop;
+ end;
+ end if;
+
+ -- Finally traverse the ELSE statements if present
+
+ Traverse_Declarations_Or_Statements
+ (Else_Statements (N), Process, Inside_Stubs);
+
+ -- Case statement
+
+ when N_Case_Statement =>
+
+ -- Process case branches
+
+ declare
+ Alt : Node_Id;
+ begin
+ Alt := First (Alternatives (N));
+ while Present (Alt) loop
+ Traverse_Declarations_Or_Statements
+ (Statements (Alt), Process, Inside_Stubs);
+ Next (Alt);
+ end loop;
+ end;
+
+ -- Extended return statement
+
+ when N_Extended_Return_Statement =>
+ Traverse_Handled_Statement_Sequence
+ (Handled_Statement_Sequence (N), Process, Inside_Stubs);
+
+ -- Loop
+
+ when N_Loop_Statement =>
+ Traverse_Declarations_Or_Statements
+ (Statements (N), Process, Inside_Stubs);
+
+ when others =>
+ null;
+ end case;
+
+ Next (N);
+ end loop;
+ end Traverse_Declarations_Or_Statements;
+
+ -----------------------------------------
+ -- Traverse_Handled_Statement_Sequence --
+ -----------------------------------------
+
+ procedure Traverse_Handled_Statement_Sequence
+ (N : Node_Id;
+ Process : Node_Processing;
+ Inside_Stubs : Boolean)
+ is
+ Handler : Node_Id;
+
+ begin
+ if Present (N) then
+ Traverse_Declarations_Or_Statements
+ (Statements (N), Process, Inside_Stubs);
+
+ if Present (Exception_Handlers (N)) then
+ Handler := First (Exception_Handlers (N));
+ while Present (Handler) loop
+ Traverse_Declarations_Or_Statements
+ (Statements (Handler), Process, Inside_Stubs);
+ Next (Handler);
+ end loop;
+ end if;
+ end if;
+ end Traverse_Handled_Statement_Sequence;
+
+ ---------------------------
+ -- Traverse_Package_Body --
+ ---------------------------
+
+ procedure Traverse_Package_Body
+ (N : Node_Id;
+ Process : Node_Processing;
+ Inside_Stubs : Boolean) is
+ begin
+ Traverse_Declarations_Or_Statements
+ (Declarations (N), Process, Inside_Stubs);
+ Traverse_Handled_Statement_Sequence
+ (Handled_Statement_Sequence (N), Process, Inside_Stubs);
+ end Traverse_Package_Body;
+
+ ----------------------------------
+ -- Traverse_Package_Declaration --
+ ----------------------------------
+
+ procedure Traverse_Package_Declaration
+ (N : Node_Id;
+ Process : Node_Processing;
+ Inside_Stubs : Boolean)
+ is
+ Spec : constant Node_Id := Specification (N);
+ begin
+ Traverse_Declarations_Or_Statements
+ (Visible_Declarations (Spec), Process, Inside_Stubs);
+ Traverse_Declarations_Or_Statements
+ (Private_Declarations (Spec), Process, Inside_Stubs);
+ end Traverse_Package_Declaration;
+
+ ------------------------------
+ -- Traverse_Subprogram_Body --
+ ------------------------------
+
+ procedure Traverse_Subprogram_Body
+ (N : Node_Id;
+ Process : Node_Processing;
+ Inside_Stubs : Boolean) is
+ begin
+ Traverse_Declarations_Or_Statements
+ (Declarations (N), Process, Inside_Stubs);
+ Traverse_Handled_Statement_Sequence
+ (Handled_Statement_Sequence (N), Process, Inside_Stubs);
+ end Traverse_Subprogram_Body;
+
+end Alfa;