TOC PREV NEXT INDEX DOC LIST MASTER INDEX



CHAPTER 4:

Customization

The Ada Analyzer was designed for customization. Software analysis often depends on many factors: the target compiler and associated development tools, the application domain, the personality of the programming team, and the customer's expectations. It is essential, therefore, that any set of analysis tools be customizable. The Ada Analyzer can be customized in four key ways:

Note: All subsystems referenced in this chapter are located in $APEX_HOME/base/ada. All units are delivered in the archived state to save space and must be compiled and re-linked.


Organization of Delivered Source Code

The Ada Analyzer source code used for customization is delivered in 4 subsystems. The following diagram illustrates the import relationships between both Ada Analyzer and Apex delivered subsystems:


Locator Templates

Simple Locator Customization

Use of the Locate_Template_Simple template is the simplest and most straightforward way to build Locate_* commands. The number of customization options available is much smaller, reducing the complexity and amount of time necessary to complete a customization.

The customization requires, at a minimum, the following definitions:

The Locate_Template_Simple package provides the following:

Note: Because of the limited customization options available in Locate_Template_Simple, it is probably most appropriate for quick customizations with requirements to locate specific items in the code. The key aspects of this customization can be moved easily to one of the other more sophisticated templates when a more stable, long-term command interface is required.

The following steps are necessary to create a new Locate_* command from the Locate_Template_Simple template. Each step is ordered to proceed through the spec of the Locate_Template_Simple package from top to bottom and then through the body from top to bottom.

1. Create a development working view. If you have already done this for a previous customization, you can use that view. It is best to create a new subsystem for local command development because it will not interfere with new releases of the Ada Analyzer. Another option is to create a working view from the latest release view, but manual changes will be required when new releases of the Ada Analyzer are delivered. If you create a new subsystem, you will need to import the latest view of the aa_utilities.ss and asis.ada95.ss subsystems into your new subsystem's working view.

2. Copy the template. Find the Locate_Template_Simple package in the locator_templates subdirectory of the ada_analyzer.ss subsystem. Use the Copy command from the File menu to copy this package into your workspace, giving it a new name.

3. Update package annotations. Change comments in the package specification as necessary to reflect the operation of the new command.

4. Determine the output filename. Change the default string name for the To_Report_Named parameter (">><<_Analysis") to a name representative of the expected output. This will be the name of the report file that your new command creates to contain the hypertable output. This string must also be updated in the body of the Display procedure.

5. Add selection or threshold parameters. Add any parameters (usually Boolean or numeric for thresholds) that you need to help steer the selection of Ada constructs. Offer a default value for each parameter that you add. Make sure to add these parameters to the body of the Display procedure as well. Compile the specification and move to the body of the new unit to complete the subsequent steps.

6. Fill in a title for the table. Fill in the following [expression] prompt with a string that you want to be the title of the resulting hypertable:

7. Update the command-logging mechanism. Modify the initial value of Command_Name and Parameters declarations to reflect the correct name of the new command and the correct parameter profile.

8. Define element attributes. Update the Columns enumeration type to contain the columns (construct attributes) for the table you want to create. Note the following:

    The Unit and Ss literals are generally included in all output. Their actual appearance in the output is governed by the analysis switches. See "Analysis Switches" on page 25 for more information. They can be deleted from the enumerated list if you do not want them included in the output.

9. Select which constructs to include in your output. Complete the body of the Include_Element function. During traversal of Ada units, you will need to decide whether each element of the unit should be included in the output. If you want the element included in the output, return True; otherwise, return False. The completion of this body requires analysis of the Asis.Element parameter with the Ada Semantic Interface Specification (ASIS) and the LRM extension packages in the aa_utilities.ss subsystem of the Ada Analyzer. See other existing Ada Analyzer commands for examples and consult "General ASIS Programming".

10. Generate attribute images. For each Ada construct entered in the hypertable, define a text image for the attribute located in the column. These images (text strings) are formed in the body of the Column_Image function. The case statement must be completed with all column enumeration literals, with each alternative returning a string image for each attribute of an included element. Images for the Unit and Ss columns are already provided as well as an example for general Asis.Element types.

11. Add explanation text. Define for each attribute in a column the explanation text, if desired. This text will be displayed in the message window when the user asks for an explanation of a particular table column with the Help:Explain command. The existing body of the Explanation function provides no explanation text (returning null string), which may be sufficient for many initial customizations.

12. Add linkage. Define for each attribute in a column the Ada construct to point to in the analyzed software unit. This linkage allows the user to execute the Visit command and traverse from the hypertable to the located construct or one of its attributes. It may also be null. The current implementation of the Linkage procedure attaches the located construct to the first column of the output. Unit column entries are attached to the unit in which the construct was found. Additional linkage can be added for each column by adding enumeration literal alternatives to the case statement and setting the Linkage out parameter to the appropriate Asis.Element value.

No other updates to your new package are required. Note that all aspects of the template are modifiable to meet local requirements. The new package should be compiled and tested before it is released to the user community. The new command must also be added to the command-line processor and graphical user interface (GUI). To accomplish this, follow the instructions in the section "Adding New Commands to the Ada Analyzer User Interface".

Full Locator Customization

Use of the Locate_Template_Full template is still straightforward, but more aspects in the content and format of the hypertable output can be modified than with the Locate_Template_Simple template. Most of these options have defaults that minimize the customization effort. Refinements to these defaults can be added later as the customization progresses.

As with the Locate_Template_Simple template, customization requires, at a minimum, the following definitions:

There are options for updating the following defaulted items:

The Locate_Template_Full template provides the following:

The following steps are necessary to customize the Locate_Template_Full template. Each step is ordered to proceed through the spec of the Locate_Template_Full package from top to bottom and then through the body from top to bottom.

1. Create a development working view. If you have already done this for a previous customization, you can use that view. It is best to create a new subsystem for local command development because it will not interfere with new releases of the Ada Analyzer. Another option is to create a working view from the latest release view, but manual changes will be required when new releases of the Ada Analyzer are delivered. If you create a new subsystem, you will need to import the latest view of the aa_utilities.ss and asis.ada95.ss subsystems into your new subsystem's working view.

2. Copy the template. Find the Locate_Template_Full package in the locator_templates subdirectory of the ada_analyzer.ss subsystem. Use the Copy command from the File menu to copy this package into your workspace, giving it a new name.

3. Update package annotations. Change comments in the package specification as necessary to reflect the operation of the new command.

4. Determine the output filename. Change the default string name for the To_Report_Named parameter (">><<_Analysis") to a name representative of the expected output. This will be the name of the report file that your new command creates to contain the hypertable output. This string must also be updated in the body of the Display procedure.

5. Add selection or threshold parameters. Add any parameters (usually Boolean or numeric parameters for thresholds) that you need to help steer the selection of Ada constructs. Offer a default value for each parameter that you add to the Display specification. These same parameters (without defaults) should be added to the Initialize procedure in the External_Traversal package. Make sure to add these parameters to the bodies of the Display and Initialize procedures as well.

6. Compile the package specification. Code the specification and move to the body of the new package to complete the subsequent steps in this list.

7. Make parameter profiles consistent. If nonstandard parameters were added to the Display and External_Traversal.Initialize procedures, pass these parameters into the call to Initialize in the body of Display.

8. Update the command-logging mechanism. Modify the initial value of Command_Name and Parameters declarations to reflect the correct name of the new command and the correct parameter profile.

9. Define a report title. Enter the desired title for the report as the initial value for the Report_Title variable, replacing the [expression] prompt.

10. Update the configuration initialization. If the computation of the size of objects or types with the Size_Utilities package is required, the Include_Type_Sizing parameter in the call to the Configuration.Initialize procedure must be changed to True. This will initialize the Sizing_Parameters to the correct values. See page 30 for more information on type sizing.

11. Select a table title. Fill in the following [expression] prompt with a string that you want to appear in the actual title of the resulting hypertable. Note that this is different from the report title above. Either can be set to the null string to avoid confusion in the output.

12. Define element attributes. Update the Columns enumeration type to contain the columns (construct attributes) for the table you want to create. Note the following:

13. Define a description of the table. The body of the Description function should return text that described the contents of the hypertable output.

14. Select the constructs to include. Complete the body of the Included procedure. During traversal of Ada units, you will need to decide whether each element of the unit should be included in the output. Set the Include out parameter to True if you want the current element included in the output; set it to False otherwise. The completion of this body requires analysis of the Asis.Element parameter with the Ada Semantic Interface Specification (ASIS) and the LRM extension packages in the aa_utilities.ss subsystem of the Ada Analyzer. See other existing Ada Analyzer commands for examples and consult "General ASIS Programming". The Continue_Deeper parameter can be set to False if no further traversal is required or desired when a particular construct is located.

15. Determine column type. The Is_Integer_Valued function allows the customizer to specify that all entries in a particular column will have an integer value and that they should be sorted by that value and not by their string image. The Is_Real_Valued function allows the customizer to specify that all entries in a particular column will have a real value and that they should be sorted by that value and not by their string image. This value is valid only when the Is_Integer_Valued function result is False for the same column (that is, Is_Integer_Valued has priority).

16. Define column headers. The Header_Image function allows the customizer the option of specifying precise header text for each column. The default is the image of the enumeration literal for that column.

17. Generate attribute images. For each Ada construct entered in the hypertable, a text image for column must be provided. These are formed in the body of the Column_Image function. The case statement must be completed with all column enumeration literals, with each alternative returning a string image of that attribute of the included element. Images for the Unit and Ss columns are already provided as well as an example for general Asis.Element types.

18. Add explanation text. Each column can also be given explanatory text. This text will be displayed in the message window when the user asks for explanation of a particular column header (see "Traversal and Explanation" on page 13). The existing body of the Explanation function provides no explanatory text (returning null strings), which may be sufficient for many initial customizations.

19. Add linkage. Each column can also be attached to Ada constructs in the analyzed software unit if desired. The current implementation of the Linkage body attaches the located construct to the first column of the output. Unit column entries are attached to the compilation unit in which the construct was found. Linkage can be added for each column (enumeration literals of the case). Note that multiple elements can be attached to a column with the Linkage_List parameter.

20. Define column sort order. The Sort procedure defines the sort order for each of the two predefined sort options. The body of this procedure must be completed when additional columns are defined in the table.

    If nonstandard parameters are added to the External_Traversal.Initialize procedure, these need to be stored globally in the External_Traversal package so that other procedures and functions (especially Include) can see their values. Although this style is generally considered less than ideal, it is the easiest and most viable method to use in this case.

No other updates generally are required. Note that all aspects of the template are modifiable to match local requirements. The new package should be compiled and tested before it is released to the user community. The new command must also be added to the command-line processor and graphical user interface. To accomplish this, follow the instructions in the section "Adding New Commands to the Ada Analyzer User Interface".

Multiple-Table Locator Customization

Use of the Locate_Template_Full_Multiple_Tables is almost identical to that for the Locate_Template_Full. The customization steps are the same except for the following additions and changes:

11.  Select a table title. With multiple tables in the report, a base title must be defined instead of a title for the single table. The initial value of the Base_Title variable must be defined, replacing the [expression] prompt.

12a.  Complete the Table_Kind type. An additional enumeration type (Table_Kind) is defined to list each possible hypertable of the output. This enumeration should have one literal for each desired table and one additional literal to represent No_Table or that the element should not be included in any table.

14.  Select the constructs to include. The Included procedure is replaced with the Which_Table procedure. Instead of returning whether to include the element in a single table, the body of this procedure must specify which table should contain the construct. The No_Table option indicates that the element should not be included in any table.

15󈝿. Complete table-entry functions. The functions Header, Is_Integer_Valued, Is_Real_Valued, Element_Image, Explanation, and Linkage have one additional parameter specifying the table in which the element has been designated to appear by the Which_Table procedure. Returned values must now take into account the table in which the item appears (that is, another nested case is usually required). See other multiple-table command implementations for examples.

21. Store steering parameters. In most cases with commands generating multiple tables, it is useful to include Boolean option parameters that give the user the ability to include the table in the final output or leave it out if it is not interesting. A standard method for this in all existing multitable commands is to create a Boolean array indexed by the Table_Kind enumeration. Each array entry is set to True or False depending on the parameter selection by the user. The Which_Table procedure checks just before it returns to see if the Table_Kind selected for the element is to be included in the output. If not, the returned Table_Kind is set to No_Table, thus eliminating it from the output. See multiple-table command implementations for examples.


Building Reports with Multiple Analysis Tables

It is possible to combine the output of several analysis commands into one report. This might be done to create a project deliverable or to create an internal status document. All Locate_* command packages in the Ada Analyzer are constructed with a nested package External_Traversal. The standard format of this package is:

package External_Traversal is
    procedure Initialize;
    procedure Register_Current_Unit (Unit : Object.Handle);
    procedure Examine_Element (Elem : Ada_Program.Element;
                               Continue_Traversal : out Boolean);
    procedure Sort (With_Sort_Order : Analysis_Switches.Sort_Orders);
    procedure Add_To_Document (Doc : in out Abstract_Document.Handle);
end External_Traversal;

Use of this interface allows one externally provided traversal mechanism to make one pass through a set of Ada units, passing each element to the Examine_Element of this package. Hypertable entries are stored in this package and can be added to any report after all traversal is complete. Tables also can be sorted with the Sort procedure. The Build_Report_Template package offers a template for building such a combined document.

The customizer must define:

The Build_Report_Template package provides the following:

Each individual command implementation defines the following:

Note: The following list is already implemented in existing commands and is not part of the customization procedure.

The following steps are necessary to customize the Build_Report_Template template. Each step is ordered to proceed through the spec of the Build_Report_Template package from top to bottom and then through the body from top to bottom.

1. Create a development working view. If you have already done this for a previous customization, you can use that view. It is best to create a new subsystem for local command development because it will not interfere with new releases of the Ada Analyzer. Another option is to create a working view from the latest release view, but manual changes will be required when new releases of the Ada Analyzer are delivered. If you create a new subsystem, you will need to import the latest view of the aa_utilities.ss and asis.ada95.ss subsystems into your new subsystem's working view.

2. Copy the template. Find the Build_Report_Template package in the locator_templates subdirectory of the ada_analyzer.ss subsystem. Use the Copy command from the File menu to copy this package into your workspace, giving it a new name.

3. Update package annotations. Change comments in the package specification as necessary to reflect the operation of the new command.

4. Determine the output report file name. Change the default string name for the To_Report_Named parameter (">><<_Report") to a name representative of the expected output. This will be the report filename that your new command creates to contain the hypertable output. This string must also be updated in the body of the Display procedure.

5. Add selection or threshold parameters. Add any parameters (usually Boolean or numeric for thresholds) that you need to help steer the selection of Ada constructs. This will probably include some selection parameters from the individual command packages. Offer a default value for each parameter that you add in the Display procedure. Make sure to add these parameters to the body of the Display procedure as well.

6. Compile the package specification. Compile the specification and move to the body of the new package to complete the subsequent steps in this list.

7. Update the command-logging mechanism. Modify the initial value of Command_Name and Parameters declarations to reflect the correct name of the new command and the correct parameter profile.

8. Define a report title. Enter the desired title for the report as the initial value for the Report_Title variable, replacing the [expression] prompt.

9. Update the configuration initialization. If computation of the size of objects or types with the Size_Utilities package is required, the Include_Type_Sizing parameter in the call to the Configuration.Initialize procedure must be changed to True. This will initialize the Sizing_Parameters to the correct values. See page 30 for more information on type sizing.

10.  Complete the calls to each External_Traversal subprogram. The body of the Build_Report_Template package is constructed with its own External_Traversal package. Thus the subprograms Initialize, Register_Current_Unit, Examine_Element, Sort, and Add_To_Report must be completed with calls to each of the corresponding subprograms in the command packages selected to be included in the larger report.

11. Add report structure. If necessary, text blocks can be added to the report to help explain its content. This is accomplished with calls to the Report package interfaces. These calls should be placed in the body of the Add_To_Report procedure.

The new package should be compiled and tested before it is released to the user community. The new command must also be added to the command-line processor and graphical user interface (GUI). To accomplish this, follow the instructions in the section "Adding New Commands to the Ada Analyzer User Interface".


Adding New Compatibility
and Standards-Conformance Rules

Checks can be added to either the Locate_Coding_Violations or Locate_Compatibility_Problems commands. This is done in an upwardly compatible way by simply creating a new check from a template and integrating it into the checking harness implementation. All work is performed in the rule_library.ss subsystem. The rule_enforcement files in all active configuration-policy directories must also be updated to enable the check, but no recompilation of the Ada Analyzer commands themselves is required. The following steps are required to add a new check to one of the above commands:

1. Create a development working view. T If you have already done this for a previous customization, you can use that view. Creating a new subsystem for local check development is not efficient in this case since all checks are implemented in separate packages. New releases can be accommodated easily with the Apex Accept From or Accept Into commands. The recommended option is to create a new working view from the latest release view in the rule_library.ss subsystem.

2. Copy the template. Find the Check_Template package in the rule_library subdirectory of the rule_library.ss subsystem. Use the Copy command from the File menu to copy this package, giving it a new name.

3. Update package annotations. Change comments in the package specification as necessary to reflect the operation of the new check.

4. Select a unique number for the new check. Each check must have a unique number. This number is entered as the initial value of the Check_Number constant in the specification of your new package. To see which numbers have already been selected, check the Rule-_Catalog file in the rule_library subdirectory. This file contains a list of all currently implemented checks and their numbers. Checks have been placed into topics with 100 numbers reserved for each topic. The current topics and numbers are:

    Target_Compatibility  100 – 199
    Code_Correctness  200 – 299
    Maintainability  300 – 399
    Efficiency  400 – 499
    Readability  500 – 599
    Portability  600 – 699
    Program_Structure  700 – 799
    Program_Format  800 – 899
    Ada 9X  900 – 999
    Real-Time (Annex D)  1000-1099
    Safety/Security (Annex H) 1100-1199
    SPARK Subset Language 1200-1299

    Topics and number reservations can be added as necessary.

5. Select a name for the new check. This can be any string and should be entered as the initial value of the Check_Name constant in the specification of your new package.

6. Compile the package specification. Compile the specification and move to the body of the new package to complete the subsequent steps in this list.

7. Ignore the Check_Label procedure. This procedure is present for a future upgrade of the Ada Analyzer.

8. Complete the body of the Check procedure. For the Ada element provided in the In_Element parameter, this procedure must determine whether the element is in violation of the rule. If it is, the Violation out parameter should be set to True; if it is not a violation, the parameter should be set to False. The ASIS interfaces and the aa_utilities.ss subsystem of the Ada Analyzer should be used to make this determination. See "General ASIS Programming" for some hints on this process. Other checks in this subsystem can also provide examples of these programming techniques. If and only if the element is a violation, a short description of the problem should be copied into the Message parameter. This is best accomplished with the Unbounded.Copy procedure.

9. Complete the body of the Header function. For each check, up to three attributes may be defined. This function defines the text that will appear at the top of each column in the output table for this check. The null string should be returned for attributes that are not used for this check.

10. Complete the body of the Attribute_Image function. When an element is selected as a violation, up to three attributes for that element can be added to the table. The image of these attributes is returned by this function. If fewer than three attributes are used, a null string should be returned for attributes that are not used.

11. Add the new check to the body of the appropriate Checks package. This can be either the Compatibility_Checks package or the Standards_Conformance_Checks package, depending on the nature of your new check. Checks added to the Compatibility_Checks package will be located by the Locate_Compatibility_Problems command in the Ada Analyzer subsystem. Checks added to the Standards_Conformance_Checks package will be located by the Locate_Coding_Violations command in the Ada Analyzer subsystem. Several substeps are necessary to complete this process:

a. Add a with clause to the body of this package referencing the new check that you created.

b. Add a new enumeration element to the Checks type definition. The literal that you select will be the name required in the rule_enforcement file in the configuration policy. Currently all enumeration literals begin with Enforcement_For_.

c. Report the rule's number. Add a new case alternative to the case statement in the body of the Rule_Number function. Return the number you selected in step 4 of these instructions.

d. Report the rule's name. Add a new case alternative to the case statement in the body of the Check_Name function. Return the name you selected in step 5 of these instructions. Follow the same format as for other checks.

e. Establish a call to the new check. Add a new case alternative to the case statement in the body of the Check procedure. Call the Check procedure in the new package you created in this alternative. Follow the same format as for other checks.

f. Connect the header information. Add a new case alternative to the case statement in the body of the Header function. Call the Header function in the new package you created in this alternative. Follow the same format as for other checks.

g. Connect the attribute generation. Add a new case alternative to the case statement in the body of the Attribute_Image function. Call the Attribute_Image function in the new package you created in this alternative. Follow the same format as for other checks.

12. If you want your new check to appear in the list of coding violation options for the Locate_Specific_Coding_Violations command, you need to complete the following two steps:

a. Add an additional enumerated value to the conformance-check Boolean options section of the Option_Name type. This value must be the same as the new enumeration literal you selected in step 11b of these instructions without the Enforcement_For_ prefix. Your new enumeration literal must appear between the First_Check_Option and Last_Check_Option values. See the section "Updating the Command-Line Parser" for more information.

b. Add an Additional option entry to the dialog box definitions located in the aa.dlisp file. See the section "Adding a New Dialog Box Definition" for more information on this process. In this case, your new option must be added to the list of options for the Locate_Specific_Coding_Violations dialog box. The name added must be identical to the enumeration value you entered in the previous step.

13. Enable the new check by adding an entry in the corresponding rule_enforcement files in all active configuration-policy directories. Note that there are two files with this name, one for the Locate_Compatibility_Problems command in the compatibility subdirectory and one for the Locate_Coding_Violations command in the standards_conformance subdirectory. The format for all entries in this file is:

    where Enforcement is one of Not_Enforced, Error, or Warning. The name that you enter here should be the same as the new enumeration literal you selected in step 11b of these instructions.

    Users with their own private configuration-policy directories that want to use this new check will need to be notified of the required additions. This line must be added to all copies of this file that may exist in each user's personal configuration policy. Otherwise, the new check will not be enabled for those users.

No other updates generally are required. Note that all aspects of the template are modifiable
to match local requirements. The Ada Analyzer must be relinked before these additions will take effect. See "Relinking the Ada Analyzer" for instructions on how to do this. The new packages should be compiled and tested before full release to the user community.


Adding New Metrics to the Metrics Library

Metrics can be added to the Collect_Metrics command in an upwardly compatible way by simply creating a new metric package from a template and integrating it into the collection harness implementation. All work is performed in the metrics_library.ss subsystem. The metrics_collection_status files in all active configuration-policy directories must also be updated to enable the metric, but no recompilation of the Ada Analyzer commands themselves is required.

Note: Existing metrics in the library can be modified if the result of the metric does not match local project requirements.

The following steps are required to add a new metric:

1. Create a development working view. If you have already done this for a previous customization, you can use that view. Creating a new subsystem for local metric development is not efficient in this case, since all checks are implemented in separate packages. New releases can be accommodated easily with the Apex Accept From or Accept Into commands. The recommended option is to create a new working view from the latest release view in the metrics_library.ss subsystem.

2. Copy the template. Find the Compute_Metric_Template package in the metrics_library subdirectory of the metrics_library.ss subsystem. Use the Copy command from the File menu to copy this package, giving it a new name.

3. Update package annotations. Change comments in the package specification as necessary to reflect the operation of the new metric.

4. Select a unique number for the new metric. Each metric must have a unique number. This number is entered as the initial value of the Metric_Number constant in the specification of your new package. To see which numbers have already been selected, check the
Metrics_Catalog file in the metrics_library subdirectory. This file contains a list of all currently implemented metrics and their numbers. Metrics have been placed into topics with 100 numbers reserved for each topic. The current topics and numbers are:

    Line Counting 100�
    Subprogram_Metrics 200�

    Unit_Modifications 300-399

    OO Metrics 400-499

    Topics and number reservations can be added as necessary.

5. Select a name for the new metric. This can be any string and should be entered as the initial value of the Metric_Name constant in the specification of your new package.

6. Select the units to which the metric applies. Metrics can be appropriate for an entire compilation unit or for some sub-element of a compilation unit, such as a program unit. Select the one that applies to this metric and delete the Count procedure from the spec that does not apply.

7. Compile the package specification. Compile the specification and move to the body of the new package to complete the subsequent steps in this list.

8. Complete the body of the Count procedure. Depending on which Count procedure you kept in step 6, implement the body of this procedure. An instantiation of the appropriate traversal has already been provided. For the Ada element provided in the Program_Element parameter, this procedure must compute the value of the metric for those elements. The ASIS interfaces and the aa_utilities.ss subsystem of the Ada Analyzer should be used to make this determination. See "General ASIS Programming" for some hints on this process. Other metrics in this subsystem can also provide examples of these programming techniques.

    Note that it may be more efficient to compute several related metrics in one traversal pass and store them in a map for future lookup. In this case, the first time a compilation unit or program unit is encountered, all metrics are computed and placed in the map. Subsequent calls to Count procedures for other metrics return the value retrieved from the map. See the Line_Count_Metrics implementation for an example.

9. Add the new check to the body of the Metrics_Collection package. Several substeps are necessary to complete this process:

a. Add a with clause to the body of this package referencing the new metric that you created.

b. Add a new enumeration element to the Metric-_Names type definition. The literal that you select will be the name required in the metrics_collection_status file in the configuration policy. Currently all enumeration literals begin with Status_For_.

c. Report the metric's number. Add a new case alternative to the case statement in the body of the Metric_Number function. Return the number you selected in step 4 of these instructions.

d. Report the metric's name. Add a new case alternative to the case statement in the body of the Metric_Name function. Return the name you selected in step 5 of these instructions. Follow the same format as for other checks.

e. Establish a call to the Count procedure for the new metric. Add a new case alternative to the case statements in both bodies of the Collect_Metric procedures. Add a call to your Count procedure to the appropriate Collect_Metric (the one that applies to compilation units or elements). Raise the exception Collection_Not_Supported in the case alternative of the other procedure. Generally follow the same format as for other checks.

10. Enable the new metric by adding an entry in the corresponding metrics_collection_status files in all active configuration-policy directories. The format for all entries in this file is:

 Metric_Name => (Collection_Status => <Status>,
                Relative_Weight => <Weight>,
                Table_Name => <Name>)

    Users with their own private configuration-policy directories that want to use this new metric will need to be notified of the required additions. This line must be added to all copies of this file that may exist in each user's personal configuration policy. Otherwise, the new metric will not be enabled for those users.

No other updates generally are required. Note that all aspects of the template are modifiable
to match local requirements. The Ada Analyzer must be relinked before these additions will take effect. See "Relinking the Ada Analyzer" for instructions on how to do this. The new packages should be compiled and tested before full release to the user community.


Creating Individual Metric Reports

It can be useful to gather metrics using a separate command so that they can be collected and compared on separate schedules. Before metrics can be placed in a separate command, they must either exist or be added to the current metrics library. See the instructions in "Adding New Metrics to the Metrics Library" to create any new metrics. The following steps are necessary to customize the Collect_Metric_Template package. Each step is ordered to proceed through the spec of the Collect_Metric_Template package from top to bottom and then through the body from top to bottom.

Note: The Count_Lines_Of_Code command was built using this template. A look at the implementation of this command may provide some assistance with this process.

1. Create a development working view. If you have already done this for a previous customization, you can use that view. It is best to create a new subsystem for local command development because it will not interfere with new releases of the Ada Analyzer. Another option is to create a working view from the latest release view, but manual changes will be required when new releases of the Ada Analyzer are delivered. If you create a new subsystem, you will need to import the latest view of the aa_utilities.ss and asis.ada95.ss subsystems into your new subsystem's working view.

2. Copy the template. Find the Collect_Metric_Template package in the locator_templates subdirectory of the ada_analyzer.ss subsystem. Use the Copy command from the File menu to copy this package into your workspace, giving it a new name.

3. Update package annotations. Change comments in the package specification as necessary to reflect the operation of the new command.

4. Determine the output filename. Change the default string name for the To_Report_Named parameter ("Collected_>><<") to a name representative of the expected output. This will be the name of the report file that your new command creates to contain the hypertable output. This string must also be updated in the body of the Display procedure.

5. Compile the package specification. Code the specification and move to the body of the new package to complete the subsequent steps in this list.

6. Update the command-logging mechanism. Modify the initial value of Command_Name and Parameters declarations to reflect the correct name of the new command and the correct parameter profile.

7. Define a report title. Enter the desired title for the report as the initial value for the Report_Title variable, replacing the [expression] prompt.

8. Update the configuration initialization. If computation of the size of objects or types with the Size_Utilities package is required, the Include_Type_Sizing parameter in the call to the Configuration.Initialize procedure must be changed to True. This will initialize the Sizing_Parameters to the correct values. See page 30 for more information on type sizing.

9. Select a table name. Fill in the following [expression] prompt with a string that you want to appear in the actual title of the resulting hypertable. Note that this is different from the report title above.

10. Determine the collection status. Determine what kind of units should have metrics collected for them. Change the initial value of the Table_Status variable to your selection. Options are Collect_By_Compilation_Unit, Collect_By_Program_Unit, Collect-_By_Subprogram_Body, or Collect_By_Subprogram_And_Task_Bodies.

11. Enable the desired metrics with a call to the Metric.Enable procedure. A template call appears in the body of the Initialize procedure. Add up to five calls to Metrics.Enable for each metric you want collected by this command.

12. Update the metric number. Change the value of the The_Metric parameter to the number of the metric you want to enable. These metrics must be added to the metric library before a command is created.

13. Update the relative weight. Change the With_Relative_Weight parameter from 1 to some other integer value if desired.

No other updates generally are required. Note that all aspects of the template are modifiable to match local requirements. The new package should be compiled and tested before it is released to the user community. The new command must also be added to the command-line processor and graphical user interface. To accomplish this, follow the instructions in the section "Adding New Commands to the Ada Analyzer User Interface".


Relinking the Ada Analyzer

To make the changes or additions to the Ada Analyzer visible to users, you must relink the Ada Analyzer main program. The main program is named process_commands and is located in the ada_analyzer.ss subsystem in $AA_HOME/base/ada. If you only made changes to existing commands or added new rules to the metrics and/or rule libraries, then you only need to relink the process_commands main program with the Apex Compile:Link command.

Depending on the strategy that you chose for your development library, you may also need to create a symbolic link that points to your main program. The symbolic link must be named aa and it should replace the existing executable located in the $AA_HOME/arch/bin directory, where arch is one of sun4, rs6k_aix, sun4_solaris, hppa_hpux, mips_irix5, or alpha_osf1. Your new link should point to the process_commands executable generated by the linking process. This can be done by spawning a shell from the Tools menu and entering the following commands:

rm $AA_HOME/{arch}/bin/aa
ln -s $AA_HOME/base/ada/ada_analyzer.ss/your_view.wrk/process_commands \ 
$AA_HOME/{arch}/bin/aa


Adding New Commands to the Ada Analyzer User Interface

To add a new command to the Ada Analyzer user interface:

Each step is straightforward and follows the pattern established for all existing Ada Analyzer commands. It is recommended that you read all instructions in this section before beginning to make any changes, because several steps are related and must be consistent.

Updating the Command-Line Parser

The command-line parser is named process_commands and is located in the ada_analyzer.ss subsystem in $AA_HOME. To add a new command to this parser, perform the following steps. Each step describes modifications to the body of process_commands proceeding from top to bottom.

1. Define a command-line syntax for your new command. Each command must have a name and a series of options that correspond to command parameters. Since your new command is written in Ada, each parameter in the procedure specification will correspond to one option in the command line. Note that only Boolean, integer, and string parameters should appear in your command interface. If enumerated types are present, then a series of Boolean options must be defined that set the enumerated parameter to each value. A summary of the command-line syntax for all Ada Analyzer commands is located in "Command-Line Summary" on page 283 and can be consulted for hints on defining your command-line syntax.

2. Add a with clause for the compilation unit containing your new command to the body of the process_commands procedure.

3. Add a new literal for your command to the Command_Name enumeration type. The name of this literal should be the name of your new command suffixed with _Cmd (like all existing enumerated literals).

4. Add new literals for your command options to the Option_Name enumeration type. The list of options (enumeration literals) is segregated by kind, and it is important that new option literals be placed in the correct place. Boolean options defined to support enumerated command parameters should be placed in the first section between the First_Special-_Option and the Last_Special_Option literals. Normal Boolean options should be placed in the next section between the First_Boolean_Option and the Last_Boolean_Option literals. String options should be placed in the section between the First_String_Option and the Last_String_Option literals. Integer options should be placed in the final section between the First_Integer_Option and the Last_Integer_Option literals. Note that if existing options have the same name as your options and if they are the correct kind, they can be reused without defining a new literal.

5. Declare a variable to hold the value of any enumeration parameters. This declaration should be placed after the Option_Name declaration in the section labeled with the appropriate comment. Variables to hold Boolean, string, and integer parameters are already declared as arrays and need not be explicitly redeclared. Adding enumeration literals to the appropriate sections of the Option_Name type (step 3) adds array elements to hold these values.

6. Give integer options a default value in case they are not specified in the option string. Default values are defined in the aggregate used to initialize the Integer_Params variable. You will need to add one entry to this aggregate for each newly defined integer option. A second aggregate, initializing the Must_Be_Positive variable, must be similarly updated. If zero or negative values are not allowed for the integer options you defined, add a new aggregate component and set the value to True. If zero or negative values are valid, set the new component to False.

7. Add a case alternative (see example below) for your new command to the case statement in the Option_Supported function. All options supported by your command should be listed in the first arm of the embedded case (returning True).

 when Your_Command_Name_Cmd =>
   case Option is
     when Your_Option | To_Report_Named | Sort_By_Subsystem =>
       return True;
     when others =>
       return False;
   end case;

8. Enumeration parameter options require a little extra processing. If you do not have enumeration parameters in your command, you can skip this step. Inside the Process-_Argument procedure is a section for processing special Boolean options for enumeration parameters. A comment marks the place where this processing should be added. Boolean options set the variable for the enumerated option (declared in step 5) to one of the enumeration values. The processing for the Display_In_Bytes and Display_In_Words options provides an example of how this is done.

9. Define a default value for the To_Report_Named option. This is done after the comment --default report names:. A new case alternative should be added for your new command similar to the following:

  when Your_Command_Name_Cmd =>
   Unbounded.Copy (String_Params (To_Report_Named),
          Analysis_Switches.Analysis_Output_Directory &
          "/your_default_report_name");

10. Add a call to your new command by adding a new case alternative in the body of the process_commands procedure. The place to add the new alternative is marked with the comment --add new command calls here:. The new case alternative should be similar to the following:

 when Your_Command_Name_Cmd =>
   Your_Command_Name.Display
          (Units => Unbounded.Image (String_Params (Units)),
           Boolean_Parameter => Boolean_Params (Boolean_Option_Name),
           Integer_Parameter => Integer_Params (Integer_Option_Name),
           String_Parameter => Unbounded.Image (String_Params 
                                      (String_Parameter_Name)),
           To_Report_Named =>  Unbounded.Image (String_Params 
                                      (To_Report_Named)),
           With_Sort_Order => With_Sort_Order);

11. After all modifications are completed, relink the process_commands main program. Follow the instructions in the section "Relinking the Ada Analyzer" to complete this step.

Adding a New Dialog Box Definition

All dialog boxes are defined in the files named <command_name>.dlg located in the $AA_HOME/dialogs directory. These files define a separate dialog box for each Ada Analyzer command. An example dialog box can be found in the section titled "Command Execution through the GUI" on page 4. All dialog boxes contain the following sections or widgets:

All dialog boxes for existing Ada Analyzer commands are derived from one of five baseline dialog boxes, each containing the widgets above and some combination of optional widgets. The following optional widgets are included in the baseline dialog boxes:

Optional widget explanations:

To add a dialog box definition to the aa, complete the following steps:

1. Select one of the baseline dialog boxes that has the right combination of optional widgets. Most simple commands can use aa_Analyze where the Unit Locator specifies the units to analyze.

2. Copy the existing file to a new named file to create your new dialog box. Modify the %dialog line to create your own named dialog box:

  %dialog my_dialog_box_name aa_Analyze %use_parent_gui

3. Define the %prog named setup. This prog(ram) is run once when the dialog is started. It is typically used to hide and unhide widgets, set widget labels, and set the banner name of the dialog box. It should also be used to define the names of any thresholds. An example setup program for the Display_Call_Tree command is:

 %prog setup
   <setw,aaDisplayCallTree, AA Display Call Tree>
   <call,setStringLbl,Of_Subprogram_Or_Task>
   <call,addThreshold,To_Depth>
   <setw,loc_form*obj_label,Units_Or_Decls_Halting_Recusion>

    Other command definitions provide examples for other setup operations.

4. Define the %prog named init. This prog(ram) is run once when the dialog is started and once each time the [Reset] button is pressed. It is typically used to set initial values of widgets that should be reset. Specifically, it should be used to set the report name, define options, and set the initial values of thresholds. An example init program for the Display_Call_Tree command is:

 %prog init
   <call,globalInit>
   <call,setReportName,call_tree>
   <call,setStringVal,<arg,3>>
   <call,thresholdInit,999>
   <call,addOption,Full_Expansion,>
   <call,addOption,Collapse_Multiple_Calls_To_Same_Subprogram,SELECTED>
   <call,addOption,Sort_By_Dependency_Order,>
   <call,completeOptions>

    Note that a call to globalInit (defined in the baseline) should always be included. If options are defined, then a call to completeOptions is also required after all calls to addOption. Preselected options can be defined by including SELECTED as the last para-meter to the call to addOption. The value of <arg,3> will be a pathname sent by the action definition (defined in the next section) to the dialog box. This is typically a list of selected units to analyze.

5. Define the %prog called exec. This prog(ram) is run whenever the [Apply] or [OK] buttons are pushed. It is used to generate the UNIX command line for execution. An example exec program for the Display_Call_Tree command is:

 %prog exec
    <call,checkEntries>
     <cond,<valw,name_form*value>,,
           <dialog,er,message_dialog,,,
            You need to specify a subprogram or task  declaration.>
      <fail>>       
    <exec,apex_display -execute
          -window_to_notify <alias_key>
          -output_title "aa display_call_tree"
          aa display_call_tree
          <call,getStringVal>
          <call,getReportName>
          <call,getOptions>
          <call,getThresholds>
          <call,getObjectList>
          <cond,<valw,config_form*use_config>,
                -Use_Configuration <valw,config_form*value>,
           >>
      nowait

    If no thresholds or options are defined, then the calls to generate these option strings can be omitted. Consult the Rational Apex documentation for more information on defining dialog boxes with the dlg syntax.

Adding New Items to the Analyzer Menu

Adding a new item to the Analyzer menu is straightforward. Three menus (directory, ada, and text) must be updated corresponding to the three kinds of windows that can have Ada Analyzer menus. The files containing the menu definitions are named directory_menus, ada_menus, and text_menus, respectively. Although there are minor differences in the updates required for each menu file, all additions are essentially the same. Note also that menu definitions can exist in several places. Apex-wide definitions are located in $APEX_HOME/editor_files. User definitions are located in the ".Rational" directory in the user's home directory. Consult the Rational Apex documentation for a strategy on management of these multiple menu definitions.

The first step is to decide in which category your new command belongs. Current Ada Analyzer categories are:

 Category Full Category Name

Each category is assigned a cascading menu with the following entry in the menu file:

append cascade  window_kind.analyze.category   "Full Category Name"  char

The window_kind is either directory, ada, or text depending on which file you are updating. The char following the full category name selects one character in the full category name for quick selection. If you would like to define a new cascading menu for your command, you must select a new category name and a new full category name and add a new line to the menu file with the above format. If you want to add a new menu item to an existing category, add a line with the following format after the append cascade line for the selected category.

append pushbutton window_kind.analyze.command_name "Full Command Name..." char

The command name is normally your full command name with no underscores; the first word is lowercase and all other name segments begin with an uppercase letter. Look at the existing command names for examples.

This completes the addition of a new menu item. Remember to update the menu files for each of the directory, ada, and text window kinds. Note that it may be easier to add the required dialog actions (see instructions in next section) for a new command and then "copy and tweak" the entries for the other files. Consult the Rational Apex documentation for more information.

Adding Menu Actions

Once a new menu item is defined, an action for that menu item must also be defined. Actions are defined after all menu items are defined. Scroll to the section where you see entries with the following form to add your new action:

action command_name
  options No_Register
      apex_display -dialog diaolog_name <SELECTION_OR_CONTEXT>
end_action

These actions create a dialog box for collection of command options from the user. When the dialog box is completed, a command is issued to the command-line parser with the options selected by the user in the dialog box. (Items in italic above need to be supplied by the user.) The command_name must be the same name used in the append pushbutton menu definition (see previous section). The dialog_name must be the name of the dialog box that you defined in the previous section. Copying an existing action definition for an existing command may be the fastest method to complete a correct action definition.

Changing Report Colors

It is possible to customize the colors used for the background and the menu bar of Ada Analyzer reports. The file $APEX_HOME/app-defaults/Rational-color can be modified to change from the default color scheme of tan and sea green to another combination. Lines in this file beginning with *text.analyzer define these colors.

Creating Command-Line Scripts

The Ada Analyzer is most effective when used interactively, but it can also be used in a more batch oriented way to ensure that up-to-date analysis information is available to developers. Batch scripts can be created to invoke the Ada Analyzer in off peak hours and store the resulting analysis reports in a common area for general access.

The easiest way to create a script is to first run the Ada Analyzer using the menus and dialog boxes of the GUI. When the dialog box for a command is executed, a UNIX command line with the name of the command and all selected options is generated and executed. All command invocations are saved by Apex in the Jobs:History window. These invocations can be copied into a file. The file can then be modified slightly to create an executable script that can be scheduled to run at regular intervals.

Specifically:

1. Create a file to contain the command script and set the execution bits for the file.

2. Run the Ada Analyzer from the GUI for each command that you want to run in batch mode. Select the options for each command that you would also like executed in the script.

3. Go to the Job:History window and select a entry for a command. Select Edit:Expand to expand the command entry from the abbreviated to the expanded form. Select the expanded version, execute Edit:Copy to save it in the copy/paste buffer. Use Edit:Paste to write the command line into the script file

4. Define and environment variable called UNITS and replace the last parameter of each command with $UNITS. Something like:

UNITS = <pathname of the units to analyze>
aa Locate_Coding_Violations $UNITS

5. Scripts can of course be parameterized or programmed using all of the features of shell programming.


General ASIS Programming

Programming with the ASIS interfaces is not a trivial task —— not because the interfaces are complex but because there are so many interfaces. This is a direct result of the broad scope of the Ada programming language. While this section does not attempt to cover all topics, it provides a basic overview to help users get started programming with ASIS. The Rational ASIS documentation will also be invaluable.

The design of ASIS attempts to follow the Reference Manual for the Ada Programming Language (Ada LRM) as closely as possible. The terminology used is that of the Ada LRM when possible. Comments reference LRM sections frequently, and the organization of the packages is patterned after LRM chapters and sections when appropriate. Another essential tool for programming with ASIS is a reference copy of the Ada LRM.

Elements and Element Kinds

The base object in ASIS is the Asis.Element. Elements correspond to nodes of a hierarchical tree representation of an Ada program. Most elements of the tree have child elements, which can appear as single elements (possibly with children themselves) or as a list of elements (also possibly with children). As an example, think of an Ada object declaration as having three subparts or children:

Thus, the Ada declaration: A, B : Integer := 0; would have a corresponding tree that looks something like:

ASIS allows the user to visit elements of the tree and ask questions about each element. One key hierarchy of questions begins with: "What kind of element do I have?" Elements at the highest level are classified into the following kinds:

The function Asis_Elements.Element_Kind classifies any element into one of these element kinds. Most elements have a separate package of interfaces for processing elements of that kind, as shown in the above list. Once the client knows that an element is a declaration, for example, it can further classify the element as to what kind of declaration it is with the Asis_Declarations.Kind function. This leads to case structures like the following:

case Asis_Elements.Element_Kind (My_Element) is
    when Asis_Elements.A_Declaration =>
        case Asis_Declarations.Kind (My_Element) is
            when Asis_Declarations.A_Variable_Declaration =>
                [statement]
            when others =>
                null;
        end case;
    when Asis_Elements.A_Statement =>
        case Asis_Statements.Kind (My_Element) is
            when Asis_Statements.A_Block_Statement =>
                [statement]
            when others =>
                null;
        end case;
    when others =>
        null;
end case;

In this example, variable declarations and block statements will presumably be processed further. All other element kinds are ignored by falling into the null, when others alternative.

Processing Specific Constructs

Once this level of classification is determined, ASIS provides a set of functions for processing a specific statement, declaration, or other element kinds. For example, the following functions are available for processing object declarations:

function Names (Declaration : Asis.Declaration)
                     return Asis.Entity_Name_Definition_List;
function Object_Declaration_Definition (Declaration : Asis.Declaration)
                     return Asis.Type_Definition;
function Is_Initialized (Declaration : Asis.Declaration)
                     return Boolean;
function Initial_Value (Declaration : Asis.Declaration) 
                     return Asis.Expression;

These functions correspond to each of the three parts of an object declaration. Once classified into its kind, each element can be processed further with the provided functions. Some functions traverse to other child elements such as the Object_Type and Initial_Value functions above. Since the kind of element that will be received back for each of these functions is already known, processing can continue directly with the functions in the Asis_Type_Definitions package that accept Type_Definition elements, or with the Asis.Expressions package that accept Expression elements. Other functions, such as Is_Initialized above, simply return some additional information about the element. The exception Asis.Inappropriate_Element is raised whenever an ASIS function is passed an element that it is not intended to process. Parameter names and subtype names in the function specifications indicate what kind of input element is expected and what kind of element is returned.

Element Lists and Iterators

Lists of elements are processed with a loop iteration scheme in the following manner:

    List : constant Asis.Element_List := 
                <ASIS function returning a list>;
    An_Element : Asis.Element;
begin
    for I in List'Range loop
       An_Element := List (I);
       Process (An_Element)
    end loop;

Functions that return Element_List types generally indicate what kind of elements are in the list they return. Thus processing can continue with specific calls without first asking what kind of element is being processed.

Operations That Apply to All Elements

The ASIS packages provide some general interfaces that operate on all nodes:

Semantic References

References from one part of an Ada program to another can be traversed with the Asis_Elements.Name_Definition function. If an element references another element, the user can traverse to the referenced element with this function. (A nil element is returned if no definition traversal is possible.) For example, the user can traverse to the type declaration referenced in an object declaration with the Name_Definition function (see accompanying illustration).

A slightly more precise statement of the operation of this function is that identifier references point at identifier definitions. Traversal will arrive at the identifier definition and you must use the Enclosing_Element functions to arrive at the complete declaration element.

Summary

The preceeding sections are intended only as an overview to help customizers get started programming with ASIS. It explains some high-level design concepts of ASIS and provides a very general description. It is beyond the scope of this document to fully address this topic. ASIS is a very broad set of interfaces reflecting the breadth of the Ada language itself. Additional sources of information include:


Rational Software Corporation  http://www.rational.com
support@rational.com
techpubs@rational.com
Copyright © 1993-2000, Rational Software Corporation. All rights reserved.
TOC PREV NEXT INDEX DOC LIST MASTER INDEX DOC LIST MASTER INDEX