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:
- Templates: Templates are available for building new analysis commands. Existing code within the templates manages all Ada unit traversal, hypertable construction, sorting, and standard table entries. The user need only define the kind of items that should be included in the output, the attributes for each item, and, if desired, any special traversal connections to constructs in the Ada code. Templates are designed to be "copy and tweak" with clearly identified areas that require input or changes on the user's part. Creation of new analysis commands from templates is fully described in the next section titled "Organization of Delivered Source Code".
- Commands: Existing Ada Analyzer commands can be modified to more precisely collect information for specific project needs. This may entail adding another column to a table or changing a column's content to more precisely match local requirements. A full set of utilities makes the development of these specific commands easier. These interfaces are located in the aa_utilities.ss subsystem of the Ada Analyzer.
Almost all Ada Analyzer commands were built from one of the available templates. This makes all tools consistent, easy to understand, and easy to modify. Note that to easily accept future releases of the Ada Analyzer, it is better to copy existing commands and modify the copy than to change existing command implementations.
- Rule checks: Two commands, Locate_Compatibility_Problems and Locate_Coding_Violations, are written as a set of rules. Each rule can be independently enabled to report as an error or as a warning, or disabled completely (no checking). Over time, it is intended that the user will build up a set of checks in the rule_library directory of the rule_library.ss subsystem. These additional checks can then be easily connected into the basic checking harness. See "Standards-Conformance and Compatibility Rule Libraries" on page 299 for a complete listing of all available rules.
- Metrics: The Collect_Metrics command is a general mechanism for collecting any number of metrics from a set of Ada units. Each metric is located in a metrics library and can be enabled independently and assigned to a named hypertable in the metrics report. Over time, it is intended that the user will build up a set of metrics in the metrics_library directory of the metrics_library.ss subsystem. These additional metrics can then be easily connected into the basic collection harness. Refer to "Little Tree Consulting's Metrics Library" on page 328 for a complete listing of all available metrics.
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 CodeThe 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 TemplatesSimple 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 name of the report file in which to store output
- The title of the output table
- The Ada constructs that should or should not be included in the hypertable output
- What attributes (columns) should be collected and displayed for each Ada construct included in the table
The Locate_Template_Simple package provides the following:
- Traversal through each element of an Ada unit
- Hypertable setup and heading definition
- Explanation of and linkage to the Ada constructs located
- Sorting (left to right by column only)
- Permanent storage and display of the hypertable in a report file
- Basic error handling
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:
-- Title string for the resulting table Table_Title : constant String := [expression];
- 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:
- Six to seven literals is the practical limit for readable output.
- The order is important. Columns will appear in the table in the same order as they appear in the enumeration type. The table will also be sorted in this order, with the leftmost column being the primary sort level.
- Each column header will be the image of the corresponding enumerated literals.
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:
- The name of the report file in which to store output
- The title of the output table
- The Ada constructs that should or should not be included in the hypertable output
- What attributes (columns) should be collected and displayed for each Ada construct included in the table
There are options for updating the following defaulted items:
- Text definitions for all column headings
- Explanatory text for each Ada construct located
- Linkage (multiple elements possible) to constructs represented in each column
- Sort order associated with each of two predefined options
- Whether to sort a column by integer or float value versus sorting by string image
The Locate_Template_Full template provides the following:
- Traversal through each Ada unit
- Hypertable setup, permanent storage, and display of the hypertable in a report file
- Basic error handling
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.
-- Title string for the resulting table Table_Title : constant String := [expression];
- 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:
- Six to seven literals is the practical limit for readable output.
- 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.
- 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 TablesIt 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.
- Which tables from existing Ada Analyzer commands should be included and in what order
- Any other structure or text blocks that are required to complete the report
The Build_Report_Template package provides the following:
- Traversal through each Ada unit
- Basic error handling
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 title of each output table
- Which Ada constructs are included in each hypertable and which are not
- What attributes (columns) are collected and displayed for each Ada construct included in each table
- Text definitions for all column headings
- Explanatory text for each Ada construct located
- Linkage (multiple elements possible) to constructs represented in each column
- Sort order associated with each of two predefined options
- Whether to sort a column by integer or float value versus sorting by string image
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 RulesChecks 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- 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:
Rule_Name => Enforcement
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 LibraryMetrics 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:- 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>)
- The Metric_Name that you enter here should be the same as the new enumeration literal you selected in step 9b of these instructions.
- The placeholder <Status> can be one of Not_Enabled, Collect_By_Compilation_Unit, Collect_By_Program_Unit, Collect_By_Subprogram_Body, or Collect_By_Subprogram_And_Task_Bodies. See "Metrics-Collection Files" on page 34 for definitions of these status values.
- The placeholder <Weight> can be any integer value, where 1 indicates that no relative weighting is desired.
- The placeholder <Name> can be any string fewer than 64 characters long. All metrics with this name will be placed in the same hypertable output. Up to five metrics can be placed in the same table.
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 ReportsIt 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 AnalyzerTo 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 InterfaceTo add a new command to the Ada Analyzer user interface:
- Add your new command and its options to the command-line parser
- Relink the command-line parser
- Add a new dialog box definition to the aa.dlisp file
- Add an entry for your new command to the Analyzer menus
- Add actions to call your new dialog box definition
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:
- Configuration File: The configuration file widget is used to specify whether import closure or a named configuration file should be used during analysis. By default, the Use Import Closure button is selected. The value of the Use Configuration option is set with a call to a shell script named `current_project_configuration'. This value is extracted from the analysis switches in the user's configuration policy. See "Analysis Switches" on page 25 for more information.
- Report Name: This section defines the name of the output file containing the analysis report. Typically only simple names are provided, but full pathnames can also be used.
- Options: This section contains Boolean options that can be selected by the user. An unlimited number of options can be defined for each dialog box. Note that each optionN must match the Boolean option name expected by the command-line parser. Option definitions also allow that the option is preselected when the dialog box is first created.
- Thresholds: Each dialog box can have up to six thresholds. Each threshold can be given a name and an initial value. Note that each threshold_name must match the integer option name expected by the command-line parser.
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:
- aa_Analyze contains one Unit Locator.
- aa_AnalyzeWithLimit contains two Unit Locators.
- aa_AnalyzeWithThresholds contains one Unit Locator and threshold fields.
- aa_AnalyzeRepair is identical to aa_Analyze but with names suitable for Ada Repair.
- aa_Template is used for testing only.
- Name Field (String Parameter): This widget appears at the top of the dialog box and is used to collect a string parameter or declaration pathname. The label of this field can be set along with its initial value. Note that the label must match the string option name expected by the command-line parser.
- Unit Locators: These are standard Apex file locators and are used to specify which Ada units should be analyzed by a command and possibly a second set of Ada units that are used to limit the effect of the command.
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>- 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>,
>>
nowaitAdding 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:
- correctness Code Correctness
- design Design & System Structure
- efficiency Efficiency & Optimization
- execution Execution Analysis
- metrics Metrics Collection
- portability Portability
- content Program Content
- readability Readability
- complexity Software Complexity
- conformance Standards Conformance
- config Configuration Policy
Each category is assigned a cascading menu with the following entry in the menu file:
append cascade window_kind.analyze.category "Full Category Name" charThe 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..." charThe 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_actionThese 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.
- 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 ProgrammingProgramming 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:
- A list of identifiers
- A reference to a type (subtype indication)
- An initial value (possibly null)
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:
- A_Pragma LRM 2.8 Asis.Elements
- An_Argument_Association LRM 2.8 Asis.Statements
- A_Declaration LRM 3 Asis.Declarations
- An_Entity_Name_Definition LRM 3.1 Asis.Declarations
- A_Type_Definition LRM 3.3.1 Asis.Type_Definitions
- A_Subtype_Indication LRM 3.3.2 Asis.Type_Definitions
- A_Constraint LRM 3.3.2 Asis.Type_Definitions
- A_Discrete_Range LRM 3.6 Asis.Type_Definitions
- A_Discriminant_Association LRM 3.7.2 Asis.Type_Definitions
- A_Variant_Part LRM 3.7.3 Asis.Type_Definitions
- A_Null_Component LRM 3.7.3 Asis.Type_Definitions
- A_Variant LRM 3.7.3 Asis.Type_Definitions
- A_Choice LRM 3.7.3 Asis.Type_Definitions
- A_Component_Association LRM 4.3 Asis.Expressions
- An_Expression LRM 4.4 Asis.Expressions
- A_Statement LRM 5.1 Asis.Statements
- An_If_Statement_Arm LRM 5.3 Asis.Statements
- A_Case_Statement_Alternative LRM 5.4 Asis.Statements
- A_Parameter_Association LRM 6.4 Asis.Statements
- A_Use_Package_Clause LRM 8.4 Asis.Compilation_Units
- A_Select_Statement_Arm LRM 9.7 Asis.Statements
- A_Select_Alternative LRM 9.7.1 Asis.Statements
- A_With_Clause LRM 10.1.1 Asis.Compilation_Units
- An_Exception_Handler LRM 11.2 Asis.Statements
- A_Representation_Clause LRM 13.1 Asis.Repr_Clauses
- A_Component_Clause LRM 13.4 Asis.Repr_Clauses
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:
- Asis_Elements.Enclosing_Element: Returns the element that contains the current element (one element up in the tree hierarchy).
- Asis.Is_Nil: Determines whether an element is nil. Some functions return a nil element when a potential element does not exist in the actual program. This is true for the Initial_Value function above when no initial value is present in the declaration.
- Asis_Text.Image: Returns the string image of any element.
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:
- ASIS documentation
- Comments in ASIS packages
- Example use of ASIS in the implementation of the Ada Analyzer (Show_Usage can help greatly here)
- Little Tree Consulting, (406) 854-2160, will be happy to provide information about any topic and answer any questions you may have.
Rational Software Corporation
http://www.rational.com support@rational.com techpubs@rational.com Copyright © 1993-2000, Rational Software Corporation. All rights reserved. |