Difference between revisions of "CA Library Implementation"
m (Stefan moved page User:Stefan/Code Analysis/Architectural Overview to User:Stefan/Code Analysis/Library Implementation) |
m |
||
Line 1: | Line 1: | ||
− | <center><small>[[User:Stefan/Code Analysis/Adding New Rules|<< 6. Adding New Rules]] |</small></center> | + | <center><small>[[User:Stefan/Code Analysis/Adding New Rules|<< 6. Adding New Rules]] | [[User:Stefan/Code Analysis/UI Implementation|8. UI Implementation > >]]</small></center> |
---- | ---- | ||
<br /> | <br /> |
Revision as of 03:07, 7 March 2014
The code for Code Analysis is located at three different places in the EVE source:
- The framework—the by far largest part, with the rule checking, the rules, the control flow graph functionality, and more—is represented as a library;
- The graphical user interface can be found in the interface cluster of EVE;
- The command-line interface for code analysis is a single class in the tty cluster of EVE.
Contents
code_analysis library
The whole code analysis framework is located in the library code_analysis.
Interface
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class CA_CODE_ANALYZER
, so a client must have or access an instance of this class. Before the analyzer can be launched all the classes that shall be analyzed must be added using one of the following features. If you use more than one of these commands then the added classes from all commands will be conjoined.
-
{CA_CODE_ANALYZER}.add_whole_system
- Adds all the classes that are part of the current system. Classes of referenced libraries will not be added. So, for example, if your system consists of the classes
MY_MAIN
,MY_BOX
, andMY_ITEM
then these three classes will be added to the list of classes to be analyzed. -
.add_class (a_class: attached CONF_CLASS)
- Adds a single class.
-
.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])
- Adds a list of classes.
-
.add_cluster (a_cluster: attached CLUSTER_I)
- Adds all classes of a cluster (and all the classes of the sub-clusters recursively).
-
.add_group (a_group: attached CONF_GROUP)
- Adds all classes of a configuration group. An example of a configuration group is a library.
Here are other features which can be called before starting to analyze:
-
{CA_CODE_ANALYZER}.clear_classes_to_analyze
- Removes all classes that have been added to the list of classes to analyze.
-
.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])
- Adds
`a_action'
to the list of procedures that will be called when analysis has completed. The procedures have one argument, a list of exceptions (with the corresponding class). In the case an exception is thrown during analysis the exception is caught by the code analyzer and is added to this list. In the graphical user interface such exceptions would show up as errors at the top of the list of rule violations. -
.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])
- Adds
`a_action'
to the procedures that are called for outputting the status. The final results (rule violations) are not given to these procedures. These output actions are used by the command-line mode and by the status bar in the GUI. -
.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN
- Tells whether
`a_rule'
will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).
Then, to start analyzing simply call {CA_CODE_ANALYZER}.analyze
.
Rule checking
In the GUI we want to be able to continue to work while the code analyzer is running. Analyzing larger sets of classes (such as whole libraries) can take from several seconds to several minutes. For this reason the code analyzer uses an asynchronous task, {CA_RULE_CHECKING_TASK}
. In {CA_CODE_ANALYZER}.analyze
this task (l_task
) is invoked as follows:
In {CA_CODE_ANALYZER}.analyze
:
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed) l_task.set_output_actions (output_actions) rota.run_task (l_task)
{CA_RULE_CHECKING_TASK}
essentially runs the whole analysis. Like all other conformants to {ROTA_TASK_I}
this class executes a series of steps between which the user interface gets some time to process its events. In {CA_RULE_CHECKING_TASK}
each step analyses one class. This means that a class is checked by all the rules for violations. The following code does that:
From {CA_RULE_CHECKING_TASK}
:
step -- <Precursor> do if has_next_step then -- Gather type information type_recorder.clear type_recorder.analyze_class (classes.item) context.set_node_types (type_recorder.node_types) context.set_checking_class (classes.item) across rules as l_rules loop -- If rule is non-standard then it will not be checked by l_rules_checker. -- We will have the rule check the current class here: if l_rules.item.is_enabled.value and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule then l_cfg_rule.check_class (classes.item) end end -- Status output. if output_actions /= Void then output_actions.call ([ca_messages.analyzing_class (classes.item.name)]) end rules_checker.run_on_class (classes.item) classes.forth has_next_step := not classes.after if not has_next_step then completed_action.call ([exceptions]) end end rescue -- Instant error output. if output_actions /= Void then output_actions.call ([ca_messages.error_on_class (classes.item.name)]) end exceptions.extend ([exception_manager.last_exception, classes.item]) -- Jump to the next class. classes.forth has_next_step := not classes.after if not has_next_step then completed_action.call ([exceptions]) end retry end
type_recorder
is of type {CA_AST_TYPE_RECORDER}
. It uses a functionality of the Eiffel compiler to determine the type of some AST nodes in the current class. The AST itself (as provided by the Eiffel compiler) does not contain any type information. context
has type {CA_ANALYSIS_CONTEXT}
and contains any side-information such as the previously mentioned types and the current class. The rules were given this context before so that they can access it when needed.
The across
loop only checks control flow graph rules. All the standard rules are checked by the line rules_checker.run_on_class (classes.item)
. rules_checker
has type {CA_ALL_RULES_CHECKER}
. This is the class where each rule must register the AST nodes the rule visits. run_on_class
iterates over the AST and calls all the actions that were registered by the standard rules. So this is the way all rules are used to check the current class. step
is executed repeatedly until there are no classes left to analyze.
In the rescue
clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.
Graphical User Interface
The classes of the graphical user interface of the code analyzer are all located in the interface cluster of EVE, in the subfolder graphical > tools > code_analysis. Here is a short overview of what the single classes do:
-
{ES_CODE_ANALYSIS_TOOL}
- Represents the code analysis GUI tool. Contains the tool title and icon, otherwise not much interesting stuff.
-
{ES_CODE_ANALYSIS_TOOL_PANEL}
- The graphical panel for the code analysis tool. It contains buttons, labels, the rule violations table view, and other user interface elements.
-
{ES_CODE_ANALYSIS_COMMAND}
- The command to launch the code analyzer. It can be added to toolbars and menus. It can be executed using stones. This class also handles the caching.
-
{ES_CODE_ANALYSIS_BENCH_HELPER}
- A helper class for the integration of the code analysis tool. It contains shared instances of
{CA_CODE_ANALYZER}
and{ES_CODE_ANALYSIS_COMMAND}
, which are used by the GUI. -
{ES_CA_SHOW_PREFERENCES_COMMAND}
- The command is used by the Preferences button in the panel.
-
{ES_CA_FIX_EXECUTOR}
- This class fixes a rule violation that has been found by the code analysis tool.
Caching
Command-line Interface
The whole command-line functionality of the code analyzer is located in the class {EWB_CODE_ANALYSIS}
. It is located in the tty cluster of EVE. {EWB_CODE_ANALYSIS}
is invoked by {ES}
, the root class for the batch (command-line) version of EiffelStudio. In {ES}
, the invocation looks as follows:
elseif option.is_equal ("-code-analysis") then l_at_args := arguments_in_range (current_option + 1, argument_count) current_option := argument_count + 1 create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)
Any command-line arguments after -code-analysis are passed on to {EWB_CODE_ANALYSIS}
. This class, in its creation procedure, processes the arguments as described in Command Line Usage. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure execute
. EWB_CODE_ANALYSIS
of course uses the code_analysis library and the previously described interface of CA_CODE_ANALYZER
. After analysis a list of rule violations is output to the command-line. In the code it looks like this:
across l_code_analyzer.rule_violations as l_vlist loop if not l_vlist.item.is_empty then l_has_violations := True -- Always sort the rule violations by the class they are referring to. output_window.add (ca_messages.cmd_class + l_vlist.key.name + "':%N") -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting. across l_vlist.item as ic loop l_rule_name := ic.item.rule.title l_rule_id := ic.item.rule.id if attached ic.item.location as l_loc then l_line := ic.item.location.line.out l_col := ic.item.location.column.out output_window.add (" (" + l_line + ":" + l_col + "): " + l_rule_name + " (" + l_rule_id + "): ") else -- No location attached. Print without location. output_window.add (" " + l_rule_name + " (" + l_rule_id + "): ") end ic.item.format_violation_description (output_window) output_window.add ("%N") end end end if not l_has_violations then output_window.add (ca_messages.no_issues + "%N") end