summaryrefslogtreecommitdiff
path: root/gcc/ada/lib-xref.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/lib-xref.adb')
-rw-r--r--gcc/ada/lib-xref.adb784
1 files changed, 784 insertions, 0 deletions
diff --git a/gcc/ada/lib-xref.adb b/gcc/ada/lib-xref.adb
new file mode 100644
index 00000000000..f7e12ef65f1
--- /dev/null
+++ b/gcc/ada/lib-xref.adb
@@ -0,0 +1,784 @@
+------------------------------------------------------------------------------
+-- --
+-- GNAT COMPILER COMPONENTS --
+-- --
+-- L I B . X R E F --
+-- --
+-- B o d y --
+-- --
+-- $Revision: 1.56 $
+-- --
+-- Copyright (C) 1998-2001, 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 2, 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 COPYING. If not, write --
+-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
+-- MA 02111-1307, USA. --
+-- --
+-- GNAT was originally developed by the GNAT team at New York University. --
+-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
+-- --
+------------------------------------------------------------------------------
+
+with Atree; use Atree;
+with Csets; use Csets;
+with Lib.Util; use Lib.Util;
+with Namet; use Namet;
+with Opt; use Opt;
+with Sinfo; use Sinfo;
+with Sinput; use Sinput;
+with Table; use Table;
+with Widechar; use Widechar;
+
+with GNAT.Heap_Sort_A;
+
+package body Lib.Xref is
+
+ ------------------
+ -- Declarations --
+ ------------------
+
+ -- The Xref table is used to record references. The Loc field is set
+ -- to No_Location for a definition entry.
+
+ subtype Xref_Entry_Number is Int;
+
+ type Xref_Entry is record
+ Ent : Entity_Id;
+ -- Entity referenced (E parameter to Generate_Reference)
+
+ Def : Source_Ptr;
+ -- Original source location for entity being referenced. Note that
+ -- these values are used only during the output process, they are
+ -- not set when the entries are originally built. This is because
+ -- private entities can be swapped when the initial call is made.
+
+ Loc : Source_Ptr;
+ -- Location of reference (Original_Location (Sloc field of N parameter
+ -- to Generate_Reference). Set to No_Location for the case of a
+ -- defining occurrence.
+
+ Typ : Character;
+ -- Reference type (Typ param to Generate_Reference)
+
+ Eun : Unit_Number_Type;
+ -- Unit number corresponding to Ent
+
+ Lun : Unit_Number_Type;
+ -- Unit number corresponding to Loc. Value is undefined and not
+ -- referenced if Loc is set to No_Location.
+
+ end record;
+
+ package Xrefs is new Table.Table (
+ Table_Component_Type => Xref_Entry,
+ Table_Index_Type => Int,
+ Table_Low_Bound => 1,
+ Table_Initial => Alloc.Xrefs_Initial,
+ Table_Increment => Alloc.Xrefs_Increment,
+ Table_Name => "Xrefs");
+
+ function Get_Xref_Index (E : Entity_Id) return Xref_Entry_Number;
+ -- Returns the Xref entry table index for entity E.
+ -- So : Xrefs.Table (Get_Xref_Index (E)).Ent = E
+
+ -------------------------
+ -- Generate_Definition --
+ -------------------------
+
+ procedure Generate_Definition (E : Entity_Id) is
+ Loc : Source_Ptr;
+ Indx : Nat;
+
+ begin
+ pragma Assert (Nkind (E) in N_Entity);
+
+ -- Note that we do not test Xref_Entity_Letters here. It is too
+ -- early to do so, since we are often called before the entity
+ -- is fully constructed, so that the Ekind is still E_Void.
+
+ if Opt.Xref_Active
+
+ -- Definition must come from source
+
+ and then Comes_From_Source (E)
+
+ -- And must have a reasonable source location that is not
+ -- within an instance (all entities in instances are ignored)
+
+ and then Sloc (E) > No_Location
+ and then Instantiation_Location (Sloc (E)) = No_Location
+
+ -- And must be a non-internal name from the main source unit
+
+ and then In_Extended_Main_Source_Unit (E)
+ and then not Is_Internal_Name (Chars (E))
+ then
+ Xrefs.Increment_Last;
+ Indx := Xrefs.Last;
+ Loc := Original_Location (Sloc (E));
+
+ Xrefs.Table (Indx).Ent := E;
+ Xrefs.Table (Indx).Loc := No_Location;
+ Xrefs.Table (Indx).Eun := Get_Source_Unit (Loc);
+ Xrefs.Table (Indx).Lun := No_Unit;
+ end if;
+ end Generate_Definition;
+
+ ---------------------------------
+ -- Generate_Operator_Reference --
+ ---------------------------------
+
+ procedure Generate_Operator_Reference (N : Node_Id) is
+ begin
+ if not In_Extended_Main_Source_Unit (N) then
+ return;
+ end if;
+
+ -- If the operator is not a Standard operator, then we generate
+ -- a real reference to the user defined operator.
+
+ if Sloc (Entity (N)) /= Standard_Location then
+ Generate_Reference (Entity (N), N);
+
+ -- A reference to an implicit inequality operator is a also a
+ -- reference to the user-defined equality.
+
+ if Nkind (N) = N_Op_Ne
+ and then not Comes_From_Source (Entity (N))
+ and then Present (Corresponding_Equality (Entity (N)))
+ then
+ Generate_Reference (Corresponding_Equality (Entity (N)), N);
+ end if;
+
+ -- For the case of Standard operators, we mark the result type
+ -- as referenced. This ensures that in the case where we are
+ -- using a derived operator, we mark an entity of the unit that
+ -- implicitly defines this operator as used. Otherwise we may
+ -- think that no entity of the unit is used. The actual entity
+ -- marked as referenced is the first subtype, which is the user
+ -- defined entity that is relevant.
+
+ else
+ if Nkind (N) = N_Op_Eq
+ or else Nkind (N) = N_Op_Ne
+ or else Nkind (N) = N_Op_Le
+ or else Nkind (N) = N_Op_Lt
+ or else Nkind (N) = N_Op_Ge
+ or else Nkind (N) = N_Op_Gt
+ then
+ Set_Referenced (First_Subtype (Etype (Right_Opnd (N))));
+ else
+ Set_Referenced (First_Subtype (Etype (N)));
+ end if;
+ end if;
+ end Generate_Operator_Reference;
+
+ ------------------------
+ -- Generate_Reference --
+ ------------------------
+
+ procedure Generate_Reference
+ (E : Entity_Id;
+ N : Node_Id;
+ Typ : Character := 'r';
+ Set_Ref : Boolean := True;
+ Force : Boolean := False)
+ is
+ Indx : Nat;
+ Nod : Node_Id;
+ Ref : Source_Ptr;
+ Def : Source_Ptr;
+ Ent : Entity_Id;
+
+ begin
+ pragma Assert (Nkind (E) in N_Entity);
+
+ -- Never collect references if not in main source unit. However,
+ -- we omit this test if Typ is 'e', since these entries are
+ -- really structural, and it is useful to have them in units
+ -- that reference packages as well as units that define packages.
+
+ if not In_Extended_Main_Source_Unit (N)
+ and then Typ /= 'e'
+ then
+ return;
+ end if;
+
+ -- Unless the reference is forced, we ignore references where
+ -- the reference itself does not come from Source.
+
+ if not Force and then not Comes_From_Source (N) then
+ return;
+ end if;
+
+ -- Deal with setting entity as referenced, unless suppressed.
+ -- Note that we still do Set_Referenced on entities that do not
+ -- come from source. This situation arises when we have a source
+ -- reference to a derived operation, where the derived operation
+ -- itself does not come from source, but we still want to mark it
+ -- as referenced, since we really are referencing an entity in the
+ -- corresponding package (this avoids incorrect complaints that the
+ -- package contains no referenced entities).
+
+ if Set_Ref then
+ Set_Referenced (E);
+
+ -- If this is a subprogram instance, mark as well the internal
+ -- subprogram in the wrapper package, which may be a visible
+ -- compilation unit.
+
+ if Is_Overloadable (E)
+ and then Is_Generic_Instance (E)
+ and then Present (Alias (E))
+ then
+ Set_Referenced (Alias (E));
+ end if;
+ end if;
+
+ -- Generate reference if all conditions are met:
+
+ if
+ -- Cross referencing must be active
+
+ Opt.Xref_Active
+
+ -- The entity must be one for which we collect references
+
+ and then Xref_Entity_Letters (Ekind (E)) /= ' '
+
+ -- Both Sloc values must be set to something sensible
+
+ and then Sloc (E) > No_Location
+ and then Sloc (N) > No_Location
+
+ -- We ignore references from within an instance
+
+ and then Instantiation_Location (Sloc (N)) = No_Location
+
+ -- Ignore dummy references
+
+ and then Typ /= ' '
+ then
+ if Nkind (N) = N_Identifier
+ or else
+ Nkind (N) = N_Defining_Identifier
+ or else
+ Nkind (N) in N_Op
+ or else
+ Nkind (N) = N_Defining_Operator_Symbol
+ or else
+ (Nkind (N) = N_Character_Literal
+ and then Sloc (Entity (N)) /= Standard_Location)
+ or else
+ Nkind (N) = N_Defining_Character_Literal
+ then
+ Nod := N;
+
+ elsif Nkind (N) = N_Expanded_Name
+ or else
+ Nkind (N) = N_Selected_Component
+ then
+ Nod := Selector_Name (N);
+
+ else
+ return;
+ end if;
+
+ -- Normal case of source entity comes from source
+
+ if Comes_From_Source (E) then
+ Ent := E;
+
+ -- Entity does not come from source, but is a derived subprogram
+ -- and the derived subprogram comes from source, in which case
+ -- the reference is to this parent subprogram.
+
+ elsif Is_Overloadable (E)
+ and then Present (Alias (E))
+ and then Comes_From_Source (Alias (E))
+ then
+ Ent := Alias (E);
+
+ -- Ignore reference to any other source that is not from source
+
+ else
+ return;
+ end if;
+
+ -- Record reference to entity
+
+ Ref := Original_Location (Sloc (Nod));
+ Def := Original_Location (Sloc (Ent));
+
+ Xrefs.Increment_Last;
+ Indx := Xrefs.Last;
+
+ Xrefs.Table (Indx).Loc := Ref;
+ Xrefs.Table (Indx).Typ := Typ;
+ Xrefs.Table (Indx).Eun := Get_Source_Unit (Def);
+ Xrefs.Table (Indx).Lun := Get_Source_Unit (Ref);
+ Xrefs.Table (Indx).Ent := Ent;
+ end if;
+ end Generate_Reference;
+
+ --------------------
+ -- Get_Xref_Index --
+ --------------------
+
+ function Get_Xref_Index (E : Entity_Id) return Xref_Entry_Number is
+ begin
+ for K in 1 .. Xrefs.Last loop
+ if Xrefs.Table (K).Ent = E then
+ return K;
+ end if;
+ end loop;
+
+ -- not found, this happend if the entity is not in the compiled unit.
+
+ return 0;
+ end Get_Xref_Index;
+
+ -----------------------
+ -- Output_References --
+ -----------------------
+
+ procedure Output_References is
+ Nrefs : constant Nat := Xrefs.Last;
+
+ Rnums : array (0 .. Nrefs) 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 these entries
+ -- 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
+
+ function Lt (Op1, Op2 : Natural) return Boolean is
+ T1 : Xref_Entry renames Xrefs.Table (Rnums (Nat (Op1)));
+ T2 : Xref_Entry renames Xrefs.Table (Rnums (Nat (Op2)));
+
+ begin
+ -- First test. If entity is in different unit, sort by unit
+
+ if T1.Eun /= T2.Eun then
+ return Dependency_Num (T1.Eun) < Dependency_Num (T2.Eun);
+
+ -- Second test, within same unit, sort by entity Sloc
+
+ elsif T1.Def /= T2.Def then
+ return T1.Def < T2.Def;
+
+ -- Third test, sort definitions ahead of references
+
+ elsif T1.Loc = No_Location then
+ return True;
+
+ elsif T2.Loc = No_Location then
+ return False;
+
+ -- Fourth test, for same entity, sort by reference location unit
+
+ elsif T1.Lun /= T2.Lun then
+ return Dependency_Num (T1.Lun) < Dependency_Num (T2.Lun);
+
+ -- Fifth test order of location within referencing unit
+
+ elsif T1.Loc /= T2.Loc then
+ return T1.Loc < T2.Loc;
+
+ -- Finally, for two locations at the same address, we 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.
+
+ else
+ return T2.Typ = 'r';
+ end if;
+ end Lt;
+
+ procedure Move (From : Natural; To : Natural) is
+ begin
+ Rnums (Nat (To)) := Rnums (Nat (From));
+ end Move;
+
+ -- Start of processing for Output_References
+
+ begin
+ if not Opt.Xref_Active then
+ return;
+ end if;
+
+ -- Capture the definition Sloc values. We delay doing this till now,
+ -- since at the time the reference or definition is made, private
+ -- types may be swapped, and the Sloc value may be incorrect. We
+ -- also set up the pointer vector for the sort.
+
+ for J in 1 .. Nrefs loop
+ Rnums (J) := J;
+ Xrefs.Table (J).Def :=
+ Original_Location (Sloc (Xrefs.Table (J).Ent));
+ end loop;
+
+ -- Sort the references
+
+ GNAT.Heap_Sort_A.Sort
+ (Integer (Nrefs),
+ Move'Unrestricted_Access,
+ Lt'Unrestricted_Access);
+
+ -- Now output the references
+
+ Output_Refs : declare
+
+ Curxu : Unit_Number_Type;
+ -- Current xref unit
+
+ Curru : Unit_Number_Type;
+ -- Current reference unit for one entity
+
+ Cursrc : Source_Buffer_Ptr;
+ -- Current xref unit source text
+
+ Curent : Entity_Id;
+ -- Current entity
+
+ Curnam : String (1 .. Name_Buffer'Length);
+ Curlen : Natural;
+ -- Simple name and length of current entity
+
+ Curdef : Source_Ptr;
+ -- Original source location for current entity
+
+ Crloc : Source_Ptr;
+ -- Current reference location
+
+ Ctyp : Character;
+ -- Entity type character
+
+ Parent_Entry : Int;
+ -- entry for parent of derived type.
+
+ function Name_Change (X : Entity_Id) return Boolean;
+ -- Determines if entity X has a different simple name from Curent
+
+ function Get_Parent_Entry (X : Entity_Id) return Int;
+ -- For a derived type, locate entry of parent type, if defined in
+ -- in the current unit.
+
+ function Get_Parent_Entry (X : Entity_Id) return Int is
+ Parent_Type : Entity_Id;
+
+ begin
+ if not Is_Type (X)
+ or else not Is_Derived_Type (X)
+ then
+ return 0;
+ else
+ Parent_Type := First_Subtype (Etype (Base_Type (X)));
+
+ if Comes_From_Source (Parent_Type) then
+ return Get_Xref_Index (Parent_Type);
+
+ else
+ return 0;
+ end if;
+ end if;
+ end Get_Parent_Entry;
+
+ function Name_Change (X : Entity_Id) return Boolean is
+ begin
+ Get_Unqualified_Name_String (Chars (X));
+
+ if Name_Len /= Curlen then
+ return True;
+
+ else
+ return Name_Buffer (1 .. Curlen) /= Curnam (1 .. Curlen);
+ end if;
+ end Name_Change;
+
+ -- Start of processing for Output_Refs
+
+ begin
+ Curxu := No_Unit;
+ Curent := Empty;
+ Curdef := No_Location;
+ Curru := No_Unit;
+ Crloc := No_Location;
+
+ for Refno in 1 .. Nrefs loop
+ declare
+ XE : Xref_Entry renames Xrefs.Table (Rnums (Refno));
+ -- The current entry to be accessed
+
+ P : Source_Ptr;
+ -- Used to index into source buffer to get entity name
+
+ P2 : Source_Ptr;
+ WC : Char_Code;
+ Err : Boolean;
+ Ent : Entity_Id;
+
+ begin
+ Ent := XE.Ent;
+ Ctyp := Xref_Entity_Letters (Ekind (Ent));
+
+ -- Skip reference if it is the only reference to an entity,
+ -- and it is an end-line reference, and the entity is not in
+ -- the current extended source. This prevents junk entries
+ -- consisting only of packages with end lines, where no
+ -- entity from the package is actually referenced.
+
+ if XE.Typ = 'e'
+ and then Ent /= Curent
+ and then (Refno = Nrefs or else
+ Ent /= Xrefs.Table (Rnums (Refno + 1)).Ent)
+ and then
+ not In_Extended_Main_Source_Unit (Ent)
+ then
+ goto Continue;
+ end if;
+
+ -- For private type, get full view type
+
+ if Ctyp = '+'
+ and then Present (Full_View (XE.Ent))
+ then
+ Ent := Underlying_Type (Ent);
+
+ if Present (Ent) then
+ Ctyp := Xref_Entity_Letters (Ekind (Ent));
+ end if;
+ end if;
+
+ -- Special exception for Boolean
+
+ if Ctyp = 'E' and then Is_Boolean_Type (Ent) then
+ Ctyp := 'B';
+ end if;
+
+ -- For variable reference, get corresponding type
+
+ if Ctyp = '*' then
+ Ent := Etype (XE.Ent);
+ Ctyp := Fold_Lower (Xref_Entity_Letters (Ekind (Ent)));
+
+ -- If variable is private type, get full view type
+
+ if Ctyp = '+'
+ and then Present (Full_View (Etype (XE.Ent)))
+ then
+ Ent := Underlying_Type (Etype (XE.Ent));
+
+ if Present (Ent) then
+ Ctyp := Xref_Entity_Letters (Ekind (Ent));
+ end if;
+ end if;
+
+ -- Special handling for access parameter
+
+ if Ekind (Etype (XE.Ent)) = E_Anonymous_Access_Type
+ and then Is_Formal (XE.Ent)
+ then
+ Ctyp := 'p';
+
+ -- Special handling for Boolean
+
+ elsif Ctyp = 'e' and then Is_Boolean_Type (Ent) then
+ Ctyp := 'b';
+ end if;
+ end if;
+
+ -- Only output reference if interesting type of entity,
+ -- and suppress self references. Also suppress definitions
+ -- of body formals (we only treat these as references, and
+ -- the references were separately recorded).
+
+ if Ctyp /= ' '
+ and then XE.Loc /= XE.Def
+ and then (not Is_Formal (XE.Ent)
+ or else No (Spec_Entity (XE.Ent)))
+ then
+ -- Start new Xref section if new xref unit
+
+ if XE.Eun /= Curxu then
+
+ if Write_Info_Col > 1 then
+ Write_Info_EOL;
+ end if;
+
+ Curxu := XE.Eun;
+ Cursrc := Source_Text (Source_Index (Curxu));
+
+ Write_Info_Initiate ('X');
+ Write_Info_Char (' ');
+ Write_Info_Nat (Dependency_Num (XE.Eun));
+ Write_Info_Char (' ');
+ Write_Info_Name (Reference_Name (Source_Index (XE.Eun)));
+ end if;
+
+ -- Start new Entity line if new entity. Note that we
+ -- consider two entities the same if they have the same
+ -- name and source location. This causes entities in
+ -- instantiations to be treated as though they referred
+ -- to the template.
+
+ if No (Curent)
+ or else
+ (XE.Ent /= Curent
+ and then
+ (Name_Change (XE.Ent) or else XE.Def /= Curdef))
+ then
+ Curent := XE.Ent;
+ Curdef := XE.Def;
+
+ Get_Unqualified_Name_String (Chars (XE.Ent));
+ Curlen := Name_Len;
+ Curnam (1 .. Curlen) := Name_Buffer (1 .. Curlen);
+
+ if Write_Info_Col > 1 then
+ Write_Info_EOL;
+ end if;
+
+ -- Write column number information
+
+ Write_Info_Nat (Int (Get_Logical_Line_Number (XE.Def)));
+ Write_Info_Char (Ctyp);
+ Write_Info_Nat (Int (Get_Column_Number (XE.Def)));
+
+ -- Write level information
+
+ if Is_Public (Curent) and then not Is_Hidden (Curent) then
+ Write_Info_Char ('*');
+ else
+ Write_Info_Char (' ');
+ end if;
+
+ -- Output entity name. We use the occurrence from the
+ -- actual source program at the definition point
+
+ P := Original_Location (Sloc (XE.Ent));
+
+ -- Entity is character literal
+
+ if Cursrc (P) = ''' then
+ Write_Info_Char (Cursrc (P));
+ Write_Info_Char (Cursrc (P + 1));
+ Write_Info_Char (Cursrc (P + 2));
+
+ -- Entity is operator symbol
+
+ elsif Cursrc (P) = '"' or else Cursrc (P) = '%' then
+ Write_Info_Char (Cursrc (P));
+
+ P2 := P;
+ loop
+ P2 := P2 + 1;
+ Write_Info_Char (Cursrc (P2));
+ exit when Cursrc (P2) = Cursrc (P);
+ end loop;
+
+ -- Entity is identifier
+
+ else
+ loop
+ if Is_Start_Of_Wide_Char (Cursrc, P) then
+ Scan_Wide (Cursrc, P, WC, Err);
+ elsif not Identifier_Char (Cursrc (P)) then
+ exit;
+ else
+ P := P + 1;
+ end if;
+ end loop;
+
+ for J in
+ Original_Location (Sloc (XE.Ent)) .. P - 1
+ loop
+ Write_Info_Char (Cursrc (J));
+ end loop;
+ end if;
+
+ -- Output derived entity name if it is available
+
+ Parent_Entry := Get_Parent_Entry (XE.Ent);
+
+ if Parent_Entry /= 0 then
+ declare
+ XD : Xref_Entry renames Xrefs.Table (Parent_Entry);
+
+ begin
+ Write_Info_Char ('<');
+
+ -- Write unit number only if different from the
+ -- current one.
+
+ if XE.Eun /= XD.Eun then
+ Write_Info_Nat (Dependency_Num (XD.Eun));
+ Write_Info_Char ('|');
+ end if;
+
+ Write_Info_Nat
+ (Int (Get_Logical_Line_Number (XD.Def)));
+ Write_Info_Char
+ (Xref_Entity_Letters (Ekind (XD.Ent)));
+ Write_Info_Nat (Int (Get_Column_Number (XD.Def)));
+
+ Write_Info_Char ('>');
+ end;
+ end if;
+
+ Curru := Curxu;
+ Crloc := No_Location;
+ end if;
+
+ -- Output the reference
+
+ if XE.Loc /= No_Location
+ and then XE.Loc /= Crloc
+ then
+ Crloc := XE.Loc;
+
+ -- Start continuation if line full, else blank
+
+ if Write_Info_Col > 72 then
+ Write_Info_EOL;
+ Write_Info_Initiate ('.');
+ end if;
+
+ Write_Info_Char (' ');
+
+ -- Output file number if changed
+
+ if XE.Lun /= Curru then
+ Curru := XE.Lun;
+ Write_Info_Nat (Dependency_Num (Curru));
+ Write_Info_Char ('|');
+ end if;
+
+ Write_Info_Nat (Int (Get_Logical_Line_Number (XE.Loc)));
+ Write_Info_Char (XE.Typ);
+ Write_Info_Nat (Int (Get_Column_Number (XE.Loc)));
+ end if;
+ end if;
+ end;
+
+ <<Continue>>
+ null;
+ end loop;
+
+ Write_Info_EOL;
+ end Output_Refs;
+ end Output_References;
+
+end Lib.Xref;