	

                            ASIS/Program View Layer
 
                                Reference View


 
INTRODUCTION
------------

The purpose of the reference view is to identify the set of Ada
entities referenced within an Ada unit.  An entity is something
declared by an Ada declaration (LRM 3.1), e.g., a type, an object, a
subprogram, a task, etc.  A reference to an entity occurs in an Ada
name (LRM 4.1). The view is structured as a cross reference;
associated with each referenced entity is the set of name constructs
that refer to the entity.  Each reference is classified with respect
to the context in which it occurs.  For instance, references to
objects are classified as 'read' or 'update' depending on whether the
reference reads or changes the value of the object.

Many applications can be envisioned for the reference view.  Here are
two examples:

  * By determining the set of entities referenced in a compilation unit,
    one can determine whether each WITH context clause associated with the
    unit is truly necessary.  (If none of the visible declarations in a
    WITHed library unit are referenced, then the WITH clause is
    unnecessary.)

  * By determining the set of entities referenced in a program unit, we
    can identify any global variables (i.e., variables referenced in the
    unit but declared outside it) that are part of the unit's data
    interface. By noting which global variables are read and which are
    updated, one can determine the number of data flows into and out of
    the unit that are not subprogram/entry parameters.

The envisioned applications impose different requirements on the scope
of the view.  Consider the first example above, which is a view of an
entire compilation unit, while the second is a view of a single
program unit.  To support these different requirements, we designed
the reference view to be a view of a fragment of Ada text we call a
"declarative region part."  

A declarative region (LRM 8.1) is a logical portion of program text
that bounds the scope of declarations.  Every program unit is a
declarative region, as are other constructs such as record types and
task entries.  The text of a declarative region may be distributed
across multiple compilation units (e.g., the specification and body of
a package may not reside in the same compilation unit).

We found it useful to create a term for each such physical part - a
"declarative region part" - which is defined to be a physical,
contiguous text fragment, residing in single compilation unit, that is
a distinct part of one declarative region.  A declarative region
contains one or more non-overlapping region parts which, taken
together, comprise the entire text of the region.  For example, in the
case of a package region, there are three region parts: one for the
visible part of the spec, one for the private part, and one for the
body. (Although the visible and private parts of the spec are
physically adjacent, for certain analyses it is convenient to treat them
as separate parts.)

Depending on the application, one may want to individually analyze the
reference view created for each region part or merge the views of
several parts together for a larger aggregate of code.  For the
latter case, we provide a merge operation.  As a convenience, we also
provide an operation to create a reference view for an entire
compilation unit.


FILES
-----

This directory contains the following files:

   README (this file)
   TRAVERSAL_SPEC
   merge_region_references.2.ada
   read_reference_view.2.ada
   reference_scan.1.ada
   reference_scan.2.ada
   reference_scan.context_support.2.ada
   reference_scan.error_handling_support.2.ada
   reference_scan.scan_any.2.ada
   reference_scan.scan_any_list.2.ada
   reference_scan.scan_argument_association.2.ada
   reference_scan.scan_argument_association_list.2.ada
   reference_scan.scan_case_statement_alternative.2.ada
   reference_scan.scan_case_statement_alternative_list.2.ada
   reference_scan.scan_choice.2.ada
   reference_scan.scan_choice_list.2.ada
   reference_scan.scan_compilation_unit.2.ada
   reference_scan.scan_component_association.2.ada
   reference_scan.scan_component_association_list.2.ada
   reference_scan.scan_component_clause.2.ada
   reference_scan.scan_component_clause_list.2.ada
   reference_scan.scan_constraint.2.ada
   reference_scan.scan_context_clause_list.2.ada
   reference_scan.scan_declaration.2.ada
   reference_scan.scan_declaration_list.2.ada
   reference_scan.scan_declarative_item_list.2.ada
   reference_scan.scan_declarative_region_part.2.ada
   reference_scan.scan_discrete_range.2.ada
   reference_scan.scan_discrete_range_list.2.ada
   reference_scan.scan_discriminant_association.2.ada
   reference_scan.scan_discriminant_association_list.2.ada
   reference_scan.scan_entity_name_definition.2.ada
   reference_scan.scan_entity_name_definition_list.2.ada
   reference_scan.scan_exception_handler.2.ada
   reference_scan.scan_exception_handler_list.2.ada
   reference_scan.scan_expression.2.ada
   reference_scan.scan_expression_list.2.ada
   reference_scan.scan_if_statement_arm.2.ada
   reference_scan.scan_if_statement_arm_list.2.ada
   reference_scan.scan_null_component.2.ada
   reference_scan.scan_parameter_association.2.ada
   reference_scan.scan_parameter_association_list.2.ada
   reference_scan.scan_pragma.2.ada
   reference_scan.scan_pragma_list.2.ada
   reference_scan.scan_record_component_list.2.ada
   reference_scan.scan_representation_clause.2.ada
   reference_scan.scan_select_alternative.2.ada
   reference_scan.scan_select_statement_arm.2.ada
   reference_scan.scan_select_statement_arm_list.2.ada
   reference_scan.scan_statement.2.ada
   reference_scan.scan_statement_list.2.ada
   reference_scan.scan_subtype_indication.2.ada
   reference_scan.scan_type_definition.2.ada
   reference_scan.scan_use_clause.2.ada
   reference_scan.scan_variant.2.ada
   reference_scan.scan_variant_list.2.ada
   reference_scan.scan_variant_part.2.ada
   reference_scan.scan_with_clause.2.ada
   reference_scan.trace_support.2.ada
   reference_view.1.ada
   reference_view.2.ada
   reference_view_structures.1.ada
   scan_for_references.2.ada
   tests (directory)


VIEW SUBSYSTEM COMPONENTS
-------------------------

The reference subsystem contains 2 Ada library units in its interface.

   package Reference_View_Structures

	Declares the view data structures.

   package Reference_View

        Provides operations to create, destroy, dump a view, merge two
        views and save/restore a view on a file.

One additional unit resides in the subsystem implementation.

   package Reference_Scan

        Performs the ASIS element traversal that constructs a view.

Three test drivers are also provided to demonstrate the operation of view.

   procedure Scan_For_References

	Creates a reference view for a compilation unit.  The view
        can optionally be dumped to standard output or saved to a
        file.  A trace of the ASIS element traversal can also be 
        generated.

   procedure Read_Reference_View

        Reads a view that has previously been saved to a file and
        dumps it to standard output.  The view must be read in the 
        context of the same ASIS library that was used to create 
	the view.

   procedure Merge_Region_References

        Creates a reference view for a compilation unit by
        constructing a separate reference view for each declarative 
        region part and merging the views together.  Produces a text 
        dump of the merged view, which is identical to the view 
        created by Scan_For_References.


VIEW SUBSYSTEM DEPENDENCIES
---------------------------

The reference subsystem imports the following subsystems:

   common
   asis
   region_scan (used by driver Merge_Region_References only)

VIEW DESCRIPTION
----------------

    View Structure
    --------------

In this section we provide a conceptual overview of the reference
view data structure. It is described in detail in the specification of
package Reference_View_Structures (file reference_view_structures.1.ada).

A reference view is constructed by traversing the ASIS element
hierarchy of a declarative region part and noting all name references
encountered.  A name reference is an Expression element of one of the
following Asis.Expressions.Expression_Kinds:

   * A_Simple_Name
   * An_Operator_Symbol
   * A_Character_Literal
   * An_Enumeration_Literal

For each such element, there is a corresponding Entity_Name_Definition
element which defines the referenced entity.  The
Entity_Name_Definition element is retrieved using the query
Asis.Expressions.Name_Definition.

The reference view is an array containing an entry for each
Entity_Name_Definition element that is referenced at least once.  Each
entry contains:

   * A pointer to the Entity_Name_Definition element.
   * A pointer to each Expression element that references the
     Entity_Name_Definition.

Associated with each reference is a reference kind indicating the
context in which the reference occurs.  The reference kind is also
influenced by the type of entity referenced.  For example, a
reference to an object can have the kind A_Read or An_Update.  A
reference to an exception can be A_Raise or A_Handle.  A
total of 36 reference kinds have been defined to characterize the
different Ada entity types and their usage.

The reference context is further delineated for 1) references to type
names in a type_mark (LRM 3.3.2) and 2) read/update references to
objects.  The type_mark construct appears in many places in the Ada
syntax.  For example, a type_mark is used to specify the type of an
object in an object declaration, the return type of a function, and
the target type of a type conversion.  We associate an additional
"type mark context" kind with references of kind Type_Mark.

Read/update references to objects can also occur in many contexts.
For instance, an expression that reads an object may represent a data
flow (e.g, in an assignment statement) or test a condition for
control flow (e.g., the condition in an IF statement).  An additional
"data access context" is associated with read/update references to
indicate how the object is being used.

References to dynamically allocated objects are included in the
reference view, although in a slightly different manner. There are
actually two references involved in this case : one to the access
object containing the pointer to the dynamic object and one to the
dynamic object itself.  The first reference, which is always A_Read,
is associated with the Entity_Name_Definition of the access object.
For the second reference, the referenced element is NOT an
Entity_Name_Definition but rather the Type_Definition element for the
access type (more precisely the ground type of the access type).  This
element represents the conceptual storage collection (LRM 3.8)
containing the dynamic object.  Since dynamic objects do not in
general have a static identity, we use the identity of the access type
instead, indicating that the reference is to one of the objects in the
access type's collection.

Specific details about the identification and classification of
references is provided in the document file TRAVERSAL_SPEC. This
document describes how the view construction traversal sets the three
kind attributes discussed above as it descends through the ASIS
element hierarchy.

   View Construction
   -----------------

The package Reference_View provides two operations for constructing a
view. The first accepts an Asis.Compilation_Unit object and traverses
the entire element hierarchy to create the view.  The second operation
traverses only the elements comprising a single declarative region
part.  Both operations include parameters to control:

   * The inclusion of references occurring within pragmas.
   * Traversal of normalized vs. unnormalized associations.
   * Traversal within generic instantiations.

To create a view for a region part, it is necessary to first create an
object of the type Region_Support.Region.  (Region_Support is a
library unit in the common subsystem.)  A Region object contains two
components: an ASIS element reference and a region kind.  The element is
required to be the "head element" of the declarative region, i.e., the
root at which to begin the traversal.  The construction operation uses
the region kind to determine which children of the head element will
be traversed.

Region objects can be created by an application's element traversal as
head elements are encountered.  (Package Region_Support includes a
predicate function for identifying a head element).  Alternatively,
the region_scan subsystem, included with the PVL views, can be used.
region_scan contains a generic package which performs an element
traversal and calls a generic formal subprogram with a Region object
whenever a head element is located.  An application could instantiate
this package with a subprogram that calls the reference view
constructor with the Region.  The test driver Merge_Region_References
demonstrates how this is done.  It builds a reference view for each
region part in a compilation unit and merges the views together into a
single, compilation unit-wide view.

   Saving a View on a File
   -----------------------

Package Reference_View includes operations for saving a view on and
restoring a view from a file.  The implementation of these operations
uses the package Asis.Ids.  Asis.Ids creates a unique, persistent name
for an Asis element which can be written to secondary storage and
later used to retrieve the same element.  

Given a view, the operation Reference_View.Output actually creates two
related files. One file is of type Asis.Ids.Id_Io and the other is a
text file.  The Id_Io file is a direct I/O file containing all of the
entity definition and reference elements from the view.  The text file
records the associations between definitions and references, as well as
the reference classifications.  It uses integer index positions from
the direct I/O file as the persistent name of Asis elements.  The two
files must be kept together, as they collectively constitute the saved
view.

The operation Reference_View.Input reads the two files and re-creates
the view.  This operation requires an Asis.Library value as input;
this MUST be the same library that was used to create and save the
view. (This requirement is passed down by the Asis.Ids package.).

   Using the View
   --------------

Many applications will want to transform the raw reference view into a
form that provides the information needed for a static analysis.  For
example, suppose one wants to determine the set of objects referenced
in a program unit.  Because objects can be aliased using a renaming
declaration, it is possible that the same object could be referenced
by more than one name.  In the reference view, these references would
be distributed among several entity name definitions (i.e., the original
definition and each alias). Therefore, the analysis would have to
locate each alias and transfer its associated references to the
reference set of the original definition.  This is possible since the
view contains ASIS element references;  the ASIS operation
Asis.Declarations.Renamed_Base_Entity can be used traverse from the
alias to the original definition.

As another example, suppose an application needed to locate the set of
referenced entities that are imported from another library unit.  In
this case, the application could apply the ASIS query
Asis.Compilation_Units.Enclosing_Compilation_Unit to each entity name
definition in the view and filter out those whose library unit name
differs from the name of the analyzed unit.


TEST CASES
----------

The tests directory contains text dumps of two reference views created
by the test driver Scan_For_References.  The views were created from
two of the view construction compilation units:

   reference_view.2.ada
   refere_view_structures.1.ada

The text dump of a view lists each entity name definition and its
associated references.  Here is an excerpt from the dump of the view
created for reference_view.2.ada:

   AN_ENTITY_NAME_DEFINITION A_SIMPLE_NAME "ASIS"
       13   6 A_WITH_CLAUSE
      451  26 AN_EXPANDED_NAME
      473  26 AN_EXPANDED_NAME

Here, the name of package ASIS has been referenced three times in the
compilation unit.  For each reference, the line and column number of
the referencing name is shown, along with the reference kind.  The
reference kinds indicated that ASIS was referenced once in a WITH
clause and twice in the prefix of an expanded name.

(Note: the text dump does not tell us that ASIS is a package; however,
an application could determine this by examining the enclosing element
of the entity name definition element in the view data structure.)

Here is an excerpt from the view dump for reference_view.2.ada.  This
demonstrates how references to dynamic objects are recorded.  In this
case, the referenced entity is the type definition of the access type.
The references are to objects in the storage collection associated
with the access type:

   A_TYPE_DEFINITION AN_ACCESS_TYPE_DEFINITION "DATA_ACCESS_CONTEXT_PTR"
      494  17 AN_ATTRIBUTE
      495  12 AN_ATTRIBUTE
      500   9 A_READ (AN_ACTUAL_PARAMETER AN_ACTUAL_PARAMETER)
      650  17 AN_ATTRIBUTE
      652  16 AN_UPDATE (AN_ACTUAL_PARAMETER)
      749  12 AN_ATTRIBUTE
      750   8 AN_UPDATE (AN_ASSIGNMENT_STATEMENT_NAME)
      751  11 A_READ (AN_ASSIGNMENT_STATEMENT_EXPRESSION)
      915  19 AN_ATTRIBUTE
      916  17 AN_ATTRIBUTE
      920  12 A_READ (AN_ACTUAL_PARAMETER AN_ACTUAL_PARAMETER AN_ACTUAL_PARAMETER)

This example shows three kinds of references: An_Attribute, A_Read,
and An_Update.  An_Attribute means the reference occurred in an
attribute expression.  A_Read and An_Update mean that the value of a
dynamic object was read and set, respectively.  Notice that these
reference kinds include a data access context.  On line 750, for
instance, an object was updated as the result of being an actual
parameter in a call where the corresponding formal parameter is of
mode Out. In some cases, there can be multiple data access contexts
when the reference is deeply nested.  The reference on line 500 shows
such a case. There, the reference is an actual parameter in a function
call which is itself an actual parameter to a procedure call.  When
multiple data access contexts are recorded, the convention is to
record them in order from most specific to least specific.
