<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>https://dev.eiffel.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Stefan</id>
		<title>EiffelStudio: an EiffelSoftware project - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="https://dev.eiffel.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Stefan"/>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/Special:Contributions/Stefan"/>
		<updated>2026-05-23T10:20:08Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.24.1</generator>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=User:Stefan&amp;diff=15169</id>
		<title>User:Stefan</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=User:Stefan&amp;diff=15169"/>
				<updated>2014-05-02T10:14:54Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: update&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I am a student of Computer Science at the ETH Zürich, Switzerland. There, for my Master thesis, I created ''Inspector Eiffel'', a [[/Code Analysis/]] tool for EiffelStudio. Prior to this I earned my Bachelors degree in Mathematics from the Universität Bern, Switzerland. I also did an IT internship with an airline company.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15129</id>
		<title>CA UI Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15129"/>
				<updated>2014-03-20T14:09:17Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: new name&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Library Implementation|&amp;amp;lt;&amp;amp;lt; 7. Library Implementation]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
The classes of the graphical user interface of Inspector Eiffel are all located in the ''interface'' cluster of EiffelStudio, in the subfolder ''graphical &amp;gt; tools &amp;gt; code_analysis''. Here is a short overview of what the single classes do:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL}&amp;lt;/e&amp;gt; : Represents the code analysis GUI tool. Contains the tool title and icon, otherwise not much interesting stuff.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL_PANEL}&amp;lt;/e&amp;gt; : The graphical panel for the code analysis tool. It contains buttons, labels, the rule violations table view, and other user interface elements.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; : 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_BENCH_HELPER}&amp;lt;/e&amp;gt; : A helper class for the integration of the code analysis tool. It contains shared instances of &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;, which are used by the GUI.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_SHOW_PREFERENCES_COMMAND}&amp;lt;/e&amp;gt; : The command is used by the ''Preferences'' button in the panel.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_FIX_EXECUTOR}&amp;lt;/e&amp;gt; : This class [[User:Stefan/Code Analysis/Using Analysis Results#Fixing Rule Violations|fixes]] a rule violation that has been found by the code analysis tool.&lt;br /&gt;
&lt;br /&gt;
These are roughly the class relations for the Inspector Eiffel GUI:&lt;br /&gt;
[[File:CA GUI Diagram.png|thumb|center|650px|The most interesting class relations of the Inspector Eiffel GUI.]]&lt;br /&gt;
&lt;br /&gt;
=== Caching ===&lt;br /&gt;
&lt;br /&gt;
It is a common case that GUI users run the code analyzer again after having made some changes to the code. We do not need to analyze the same unchanged code again and again. Therefore code analysis caches the results in memory. This only applies to the GUI mode.&lt;br /&gt;
&lt;br /&gt;
Code analysis uses cached results exactly in one case: when the whole system is analyzed and the previous analysis was on the whole system, too.&lt;br /&gt;
&lt;br /&gt;
The caching functionality is implemented in &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;. When the command for analyzing the system is executed, the timestamps of the last modification of the classes are stored in &amp;lt;e&amp;gt;analysis_timestamp : HASH_TABLE [INTEGER, CLASS_I]&amp;lt;/e&amp;gt; before the analysis. Note that the cached results (the rule violations) themselves are managed by &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt;. The only difference to a non-cached analysis is that the rule violations are not deleted by &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; before the next analysis. Then, in case the next command is also for analyzing the whole system, the current timestamps are compared to the stored timestamps. Any class that has been changed in the meantime will be analyzed again; for any unchanged class the rule violations are taken from the cache.&lt;br /&gt;
&lt;br /&gt;
=== Example Command: Analyze One Class ===&lt;br /&gt;
&lt;br /&gt;
We will now roughly go through the code that is executed on the GUI part when the user wants to analyze a single class. As mentioned in Chapter [[User:Stefan/Code Analysis/Running the Analyzer|Running the Analyzer]], this can be done using the class context menu or by dropping the class stone on the button ''Analyze Item''.&lt;br /&gt;
&lt;br /&gt;
In any case &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}.execute_with_stone&amp;lt;/e&amp;gt; is called, which delegates to &amp;lt;e&amp;gt;execute_with_stone_content&amp;lt;/e&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
execute_with_stone (a_stone: STONE)&lt;br /&gt;
    -- Execute with `a_stone'.&lt;br /&gt;
  do&lt;br /&gt;
    execute_with_stone_content (a_stone, Void)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
execute_with_stone_content (a_stone: STONE; a_content: SD_CONTENT)&lt;br /&gt;
    -- Execute with `a_stone'.&lt;br /&gt;
  local&lt;br /&gt;
    l_save_confirm: ES_DISCARDABLE_COMPILE_SAVE_FILES_PROMPT&lt;br /&gt;
    l_classes: DS_ARRAYED_LIST [CLASS_I]&lt;br /&gt;
  do&lt;br /&gt;
      -- Show the tool right from the start.&lt;br /&gt;
    show_ca_tool&lt;br /&gt;
&lt;br /&gt;
    if not eiffel_project.is_compiling then&lt;br /&gt;
      if window_manager.has_modified_windows then&lt;br /&gt;
        create l_classes.make_default&lt;br /&gt;
        window_manager.all_modified_classes.do_all (agent l_classes.force_last)&lt;br /&gt;
        create l_save_confirm.make (l_classes)&lt;br /&gt;
        l_save_confirm.set_button_action (l_save_confirm.dialog_buttons.yes_button, agent save_compile_and_analyze (a_stone))&lt;br /&gt;
        l_save_confirm.set_button_action (l_save_confirm.dialog_buttons.no_button, agent compile_and_analyze (a_stone))&lt;br /&gt;
        l_save_confirm.show_on_active_window&lt;br /&gt;
      else&lt;br /&gt;
        compile_and_analyze (a_stone)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there are modified, unsaved windows a save confirmation dialog is displayed. Eventually program flow passes on to &amp;lt;e&amp;gt;compile_and_analyze&amp;lt;/e&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
compile_and_analyze (a_stone: STONE)&lt;br /&gt;
    -- Compile project and perform analysis of stone `a_stone'.&lt;br /&gt;
  local&lt;br /&gt;
    l_helper: ES_CODE_ANALYSIS_BENCH_HELPER&lt;br /&gt;
    l_dialog: ES_INFORMATION_PROMPT&lt;br /&gt;
  do&lt;br /&gt;
      -- Compile the project and only analyze if the compilation was successful.&lt;br /&gt;
    eiffel_project.quick_melt (True, True, True)&lt;br /&gt;
    if eiffel_project.successful then&lt;br /&gt;
      create l_helper&lt;br /&gt;
      if l_helper.code_analyzer.is_running then&lt;br /&gt;
        create l_dialog.make_standard (ca_messages.already_running_long)&lt;br /&gt;
        l_dialog.show_on_active_window&lt;br /&gt;
      else&lt;br /&gt;
        perform_analysis (a_stone)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;eiffel_project.quick_melt&amp;lt;/e&amp;gt; starts the compilation. A successful compilation is required for code analysis; otherwise nothing is analyzed. After compilation has succeeded we check if code analysis is already running. If this is the case then a dialog is displayed. If on the other hand this last possible obstacle is not present we finally start analyzing by calling &amp;lt;e&amp;gt;perform_analysis&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
perform_analysis (a_stone: STONE)&lt;br /&gt;
    -- Analyze `a_stone' only.&lt;br /&gt;
  local&lt;br /&gt;
    l_helper: ES_CODE_ANALYSIS_BENCH_HELPER&lt;br /&gt;
    l_scope_label: EV_LABEL&lt;br /&gt;
  do&lt;br /&gt;
      -- For simplicity let us assume that `a_stone' does not&lt;br /&gt;
      -- correspond to the system or is equivalent to it.&lt;br /&gt;
    last_was_analyze_all := False&lt;br /&gt;
&lt;br /&gt;
    create l_helper&lt;br /&gt;
    code_analyzer := l_helper.code_analyzer&lt;br /&gt;
    code_analyzer.clear_classes_to_analyze&lt;br /&gt;
    code_analyzer.rule_violations.wipe_out&lt;br /&gt;
&lt;br /&gt;
    l_scope_label := ca_tool.panel.scope_label&lt;br /&gt;
&lt;br /&gt;
    if attached {CLASSC_STONE} a_stone as s then&lt;br /&gt;
      code_analyzer.add_class (s.class_i.config_class)&lt;br /&gt;
      l_scope_label.set_text (s.class_name)&lt;br /&gt;
      l_scope_label.set_foreground_color (create {EV_COLOR}.make_with_8_bit_rgb (140, 140, 255))&lt;br /&gt;
      l_scope_label.set_pebble (s)&lt;br /&gt;
      l_scope_label.set_pick_and_drop_mode&lt;br /&gt;
      l_scope_label.set_tooltip (ca_messages.class_scope_tooltip)&lt;br /&gt;
    elseif [...]&lt;br /&gt;
    [...]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    disable_tool_button&lt;br /&gt;
    window_manager.display_message (ca_messages.status_bar_running)&lt;br /&gt;
    code_analyzer.add_completed_action (agent analysis_completed)&lt;br /&gt;
    code_analyzer.analyze&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The code that deals with stones other than classes is omitted.)&lt;br /&gt;
&lt;br /&gt;
At the start of the routine the code analyzer instance is retrieved from the helper class. All classes that may have been addedbefore, are removed. All previous rule violations are removed as well. The if clause creates a stone for the ''Last Scope'' label in the graphical panel. Then, the button in the tool is disabled so that starting another analysis is prevented until the current one has completed. Finally, the analysis is started. As soon as the analysis has completed &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}.analysis_completed&amp;lt;/e&amp;gt; is called. In this procedure the rule violations (and possibly the exceptions) are retrieved from the code analyzer and displayed in the list in the tool panel.&lt;br /&gt;
&lt;br /&gt;
== Command-Line Interface ==&lt;br /&gt;
&lt;br /&gt;
The whole command-line functionality of the code analyzer is located in the class &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. It is located in the ''tty'' cluster of EiffelStudio. &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt; is invoked by &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the root class for the ''batch'' (command-line) version of EiffelStudio. In &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the invocation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
elseif option.is_equal (&amp;quot;-code-analysis&amp;quot;) then&lt;br /&gt;
  l_at_args := arguments_in_range (current_option + 1, argument_count)&lt;br /&gt;
  current_option := argument_count + 1&lt;br /&gt;
  create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any command-line arguments after ''-code-analysis'' are passed on to &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. This class, in its creation procedure, processes the arguments as described in [[User:Stefan/Code_Analysis/Command Line Usage|Command Line Usage]]. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure &amp;lt;e&amp;gt;execute&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; of course uses the ''code_analysis'' library and the previously described interface of &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;. After analysis a list of rule violations is output to the command-line. In the code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
across l_code_analyzer.rule_violations as l_vlist loop&lt;br /&gt;
  if not l_vlist.item.is_empty then&lt;br /&gt;
    l_has_violations := True&lt;br /&gt;
      -- Always sort the rule violations by the class they are referring to.&lt;br /&gt;
    output_window.add (ca_messages.cmd_class + l_vlist.key.name + &amp;quot;':%N&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting.&lt;br /&gt;
    across l_vlist.item as ic loop&lt;br /&gt;
      l_rule_name := ic.item.rule.title&lt;br /&gt;
      l_rule_id := ic.item.rule.id&lt;br /&gt;
      if attached ic.item.location as l_loc then&lt;br /&gt;
        l_line := ic.item.location.line.out&lt;br /&gt;
        l_col := ic.item.location.column.out&lt;br /&gt;
        output_window.add (&amp;quot;  (&amp;quot; + l_line + &amp;quot;:&amp;quot; + l_col + &amp;quot;): &amp;quot;&lt;br /&gt;
          + l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      else -- No location attached. Print without location.&lt;br /&gt;
        output_window.add (&amp;quot;  &amp;quot;	+ l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      ic.item.format_violation_description (output_window)&lt;br /&gt;
      output_window.add (&amp;quot;%N&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not l_has_violations then output_window.add (ca_messages.no_issues + &amp;quot;%N&amp;quot;) end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15128</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15128"/>
				<updated>2014-03-20T14:08:24Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: new name&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] | [[User:Stefan/Code Analysis/UI Implementation|8. UI Implementation &amp;amp;gt; &amp;amp;gt;]]&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Inspector Eiffel is located at three different places in the EiffelStudio source:&lt;br /&gt;
# The framework—by far the largest part, with the rule checking, the rules, the control flow graph functionality, and more—is represented as a ''library'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of EiffelStudio;&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of EiffelStudio.&lt;br /&gt;
&lt;br /&gt;
The whole '''Inspector Eiffel framework''' is located in the '''library ''code_analysis'''''.&lt;br /&gt;
&lt;br /&gt;
== Class Relations ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows an overview of the relations between the classes of the code analysis framework. All classes are located in the ''code_analysis'' library except for &amp;lt;e&amp;gt;CLASS_C&amp;lt;/e&amp;gt; (EiffelStudio), &amp;lt;e&amp;gt;ROTA_TIMED_TASK_I&amp;lt;/e&amp;gt; (''ecosystem'' cluster), &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; (command-line interface), and &amp;lt;e&amp;gt;ES_CODE_ANALYSIS_BENCH_HELPER&amp;lt;/e&amp;gt; (GUI).&lt;br /&gt;
&lt;br /&gt;
[[File:CA Framework Diagram.png|thumb|center|800px|The most interesting classes of the code analysis framework.]]&lt;br /&gt;
&lt;br /&gt;
== Interface ==&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Rule Checking ==&lt;br /&gt;
&lt;br /&gt;
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'', &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;. In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt; this task (&amp;lt;e&amp;gt;l_task&amp;lt;/e&amp;gt;) is invoked as follows:&lt;br /&gt;
&lt;br /&gt;
=== In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed)&lt;br /&gt;
l_task.set_output_actions (output_actions)&lt;br /&gt;
rota.run_task (l_task)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; essentially runs the whole analysis. Like all other conformants to &amp;lt;e&amp;gt;{ROTA_TASK_I}&amp;lt;/e&amp;gt; this class executes a series of ''steps'' between which the user interface gets some time to process its events. In &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; each step analyses one class. This means that a class is checked by ''all'' the rules for violations. The following code does that:&lt;br /&gt;
&lt;br /&gt;
=== From &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
step&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
  do&lt;br /&gt;
    if has_next_step then&lt;br /&gt;
        -- Gather type information&lt;br /&gt;
      type_recorder.clear&lt;br /&gt;
      type_recorder.analyze_class (classes.item)&lt;br /&gt;
      context.set_node_types (type_recorder.node_types)&lt;br /&gt;
      context.set_checking_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      across rules as l_rules loop&lt;br /&gt;
          -- If rule is non-standard then it will not be checked by l_rules_checker.&lt;br /&gt;
          -- We will have the rule check the current class here:&lt;br /&gt;
        if&lt;br /&gt;
          l_rules.item.is_enabled.value&lt;br /&gt;
          and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule&lt;br /&gt;
        then&lt;br /&gt;
          l_cfg_rule.check_class (classes.item)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
        -- Status output.&lt;br /&gt;
      if output_actions /= Void then&lt;br /&gt;
        output_actions.call ([ca_messages.analyzing_class (classes.item.name)])&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      rules_checker.run_on_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      classes.forth&lt;br /&gt;
      has_next_step := not classes.after&lt;br /&gt;
      if not has_next_step then&lt;br /&gt;
        completed_action.call ([exceptions])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  rescue&lt;br /&gt;
      -- Instant error output.&lt;br /&gt;
    if output_actions /= Void then&lt;br /&gt;
      output_actions.call ([ca_messages.error_on_class (classes.item.name)])&lt;br /&gt;
    end&lt;br /&gt;
    exceptions.extend ([exception_manager.last_exception, classes.item])&lt;br /&gt;
      -- Jump to the next class.&lt;br /&gt;
    classes.forth&lt;br /&gt;
    has_next_step := not classes.after&lt;br /&gt;
    if not has_next_step then&lt;br /&gt;
      completed_action.call ([exceptions])&lt;br /&gt;
    end&lt;br /&gt;
    retry&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;type_recorder&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_AST_TYPE_RECORDER}&amp;lt;/e&amp;gt;. 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. &amp;lt;e&amp;gt;context&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;e&amp;gt;across&amp;lt;/e&amp;gt; loop only checks ''control flow graph rules''. All the ''standard'' rules are checked by the line &amp;lt;e&amp;gt;rules_checker.run_on_class (classes.item)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;rules_checker&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt;. This is the class where each rule must register the AST nodes the rule visits. &amp;lt;e&amp;gt;run_on_class&amp;lt;/e&amp;gt; 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. &amp;lt;e&amp;gt;step&amp;lt;/e&amp;gt; is executed repeatedly until there are no classes left to analyze.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;e&amp;gt;rescue&amp;lt;/e&amp;gt; clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.&lt;br /&gt;
&lt;br /&gt;
=== Checking ''Standard'' Rules ===&lt;br /&gt;
&lt;br /&gt;
The relatively large class &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; is responsible for checking ''standard rules''. It does this in a straightforward way. It is a subclass of &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt;, a realization of a visitor on the AST.&lt;br /&gt;
&lt;br /&gt;
Rules can register their actions with &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; by calling a procedure like &amp;lt;e&amp;gt;add_bin_lt_pre_action (a_action: attached PROCEDURE [ANY, TUPLE [BIN_LT_AS]])&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&amp;lt;/e&amp;gt;. These &amp;quot;pre&amp;quot; and &amp;quot;post&amp;quot; actions exist for many other types of AST nodes as well. All the registered actions are stored in &amp;lt;e&amp;gt;ACTION_SEQUENCE&amp;lt;/e&amp;gt; variables:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
if_pre_actions, if_post_actions: ACTION_SEQUENCE [TUPLE [IF_AS]]&lt;br /&gt;
&lt;br /&gt;
add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&lt;br /&gt;
  do&lt;br /&gt;
    if_post_actions.extend (a_action)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding visitor procedures are redefined. This is done is the following way:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_if_as (a_if: IF_AS)&lt;br /&gt;
  do&lt;br /&gt;
    if_pre_actions.call ([a_if])&lt;br /&gt;
    Precursor (a_if)&lt;br /&gt;
    if_post_actions.call ([a_if])&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the actual iteration over the AST is done in the ancestor we need only very little code to analyze a class:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {CA_RULE_CHECKING_TASK} -- Execution Commands&lt;br /&gt;
&lt;br /&gt;
  run_on_class (a_class_to_check: CLASS_C)&lt;br /&gt;
      -- Check all rules that have added their agents.&lt;br /&gt;
    local&lt;br /&gt;
      l_ast: CLASS_AS&lt;br /&gt;
    do&lt;br /&gt;
      last_run_successful := False&lt;br /&gt;
      l_ast := a_class_to_check.ast&lt;br /&gt;
      class_pre_actions.call ([l_ast])&lt;br /&gt;
      process_class_as (l_ast)&lt;br /&gt;
      class_post_actions.call ([l_ast])&lt;br /&gt;
      last_run_successful := True&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code analyzes a class for all active ''standard'' rules. &amp;lt;e&amp;gt;class_pre_actions&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;class_post_actions&amp;lt;/e&amp;gt; are action sequences that are identical to those for the AST nodes. &amp;lt;e&amp;gt;process_class_as&amp;lt;/e&amp;gt;, which is implemented in &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt; will recursively visit all relevant AST nodes and execute their action sequences.&lt;br /&gt;
&lt;br /&gt;
== Example: Rule # 71: ''Self-comparison'' ==&lt;br /&gt;
&lt;br /&gt;
We will go through the implementation of rule # 71 (''Self-comparison'') in detail.&lt;br /&gt;
&lt;br /&gt;
The heart of this implementation lies in the feature &amp;lt;e&amp;gt;analyze_self&amp;lt;/e&amp;gt;. There it is tested whether a binary expression is s self-comparison. &amp;lt;e&amp;gt;is_self&amp;lt;/e&amp;gt;, a &amp;lt;e&amp;gt;BOOLEAN&amp;lt;/e&amp;gt; attribute, is set to true if and only if the argument is a comparison between two identical variables.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
analyze_self (a_bin: attached BINARY_AS)&lt;br /&gt;
    -- Is `a_bin' a self-comparison?&lt;br /&gt;
  do&lt;br /&gt;
    is_self := False&lt;br /&gt;
&lt;br /&gt;
    if&lt;br /&gt;
      attached {EXPR_CALL_AS} a_bin.left as l_e1&lt;br /&gt;
      and then attached {ACCESS_ID_AS} l_e1.call as l_l&lt;br /&gt;
      and then attached {EXPR_CALL_AS} a_bin.right as l_e2&lt;br /&gt;
      and then attached {ACCESS_ID_AS} l_e2.call as l_r&lt;br /&gt;
    then&lt;br /&gt;
      is_self := l_l.feature_name.is_equal (l_r.feature_name)&lt;br /&gt;
      self_name := l_l.access_name_32&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
is_self: BOOLEAN&lt;br /&gt;
    -- Is `a_bin' from last call to `analyze_self' a self-comparison?&lt;br /&gt;
&lt;br /&gt;
self_name: detachable STRING_32&lt;br /&gt;
    -- Name of the self-compared variable.&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both sides of the comparison, &amp;lt;e&amp;gt;a_bin.left&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;a_bin.right&amp;lt;/e&amp;gt;, are tested to have the types that indicate that they are variable or feature accesses. If the tests succeed then &amp;lt;e&amp;gt;is_self&amp;lt;/e&amp;gt; is set according to the equality of the two feature names. Then the name is stored in an internal attribute.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;analyze_self&amp;lt;/e&amp;gt; is used in &amp;lt;e&amp;gt;process_comparison&amp;lt;/e&amp;gt;, which creates a rule violation if a self-comparison was detected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_comparison (a_comparison: BINARY_AS)&lt;br /&gt;
    -- Checks `a_comparison' for rule violations.&lt;br /&gt;
  local&lt;br /&gt;
    l_viol: CA_RULE_VIOLATION&lt;br /&gt;
  do&lt;br /&gt;
    if not in_loop then&lt;br /&gt;
      analyze_self (a_comparison)&lt;br /&gt;
      if is_self then&lt;br /&gt;
        create l_viol.make_with_rule (Current)&lt;br /&gt;
        l_viol.set_location (a_comparison.start_location)&lt;br /&gt;
        l_viol.long_description_info.extend (self_name)&lt;br /&gt;
        violations.extend (l_viol)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First we check that we are not dealing with a loop condition. Self-comparisons in loop conditions are more dangerous and need special treatment (see below). For the rule violation, we set the location to the start location of the binary comparison. We add the variable or feature name to the violation.&lt;br /&gt;
&lt;br /&gt;
Different kinds of comparisons also have different types in the AST. That is why in an AST iterator they are processed independently. Thus, we need to add some delegation to each of the actions that are called when processing a comparison.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_bin_eq (a_bin_eq: BIN_EQ_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_eq)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_ge (a_bin_ge: BIN_GE_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_ge)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_gt (a_bin_gt: BIN_GT_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_gt)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_le (a_bin_le: BIN_LE_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_le)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_lt (a_bin_lt: BIN_LT_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_lt)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the case that a loop condition is a self-comparison, the loop is either never entered or it is never exited. The last case is more severe; the first case only arises with an equality comparison. For this reason we analyze loop conditions separately. If we find such a violation we set &amp;lt;e&amp;gt;in_loop&amp;lt;/e&amp;gt; to &amp;lt;e&amp;gt;True&amp;lt;/e&amp;gt; so that any further self-comparisons are ignored until we have left the loop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
pre_process_loop (a_loop: LOOP_AS)&lt;br /&gt;
    -- Checking a loop `a_loop' for self-comparisons needs more work. If the until expression&lt;br /&gt;
    -- is a self-comparison that does not compare for equality then the loop will&lt;br /&gt;
    -- not terminate, which is more severe consequence compared to other self-comparisons.&lt;br /&gt;
  local&lt;br /&gt;
    l_viol: CA_RULE_VIOLATION&lt;br /&gt;
  do&lt;br /&gt;
    if attached {BINARY_AS} a_loop.stop as l_bin then&lt;br /&gt;
    analyze_self (l_bin)&lt;br /&gt;
    if is_self then&lt;br /&gt;
      create l_viol.make_with_rule (Current)&lt;br /&gt;
      l_viol.set_location (a_loop.stop.start_location)&lt;br /&gt;
      l_viol.long_description_info.extend (self_name)&lt;br /&gt;
      if not attached {BIN_EQ_AS} l_bin then&lt;br /&gt;
          -- It is only a dangerous loop stop condition if we do not have&lt;br /&gt;
          -- an equality comparison.&lt;br /&gt;
        l_viol.long_description_info.extend (&amp;quot;loop_stop&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      violations.extend (l_viol)&lt;br /&gt;
      in_loop := True&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;format_violation_description&amp;lt;/e&amp;gt;, which is declared in &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt; as &amp;lt;e&amp;gt;deferred&amp;lt;/e&amp;gt;, must be implemented. Here, together with a predefined localized text, we mention the name of the self-compared variable. If the self-comparison is located in a loop stop condition we add an additional warning text.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
  local&lt;br /&gt;
    l_info: LINKED_LIST [ANY]&lt;br /&gt;
  do&lt;br /&gt;
    l_info := a_violation.long_description_info&lt;br /&gt;
    a_formatter.add (&amp;quot;'&amp;quot;)&lt;br /&gt;
    if l_info.count &amp;gt;= 1 and then attached {STRING_32} l_info.first as l_name then&lt;br /&gt;
      a_formatter.add_local (l_name)&lt;br /&gt;
    end&lt;br /&gt;
    a_formatter.add (ca_messages.self_comparison_violation_1)&lt;br /&gt;
&lt;br /&gt;
    l_info.compare_objects&lt;br /&gt;
    if l_info.has (&amp;quot;loop_stop&amp;quot;) then&lt;br /&gt;
        -- Dangerous loop stop condition.&lt;br /&gt;
      a_formatter.add (ca_messages.self_comparison_violation_2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we must implement the usual properties.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
title: STRING_32&lt;br /&gt;
  do&lt;br /&gt;
    Result := ca_names.self_comparison_title&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
id: STRING_32 = &amp;quot;CA071&amp;quot;&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
&lt;br /&gt;
description: STRING_32&lt;br /&gt;
  do&lt;br /&gt;
    Result :=  ca_names.self_comparison_description&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, in the initialization we use the default settings, which can be set by calling &amp;lt;e&amp;gt;{CA_RULE}.make_with_defaults&amp;lt;/e&amp;gt;. To the default severity score we assign a custom value. In &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt; we must add all the agents for processing the loop and comparison nodes of the AST.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {NONE} -- Initialization&lt;br /&gt;
&lt;br /&gt;
  make&lt;br /&gt;
      -- Initialization.&lt;br /&gt;
    do&lt;br /&gt;
      make_with_defaults&lt;br /&gt;
      default_severity_score := 70&lt;br /&gt;
		  end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      a_checker.add_bin_eq_pre_action (agent process_bin_eq)&lt;br /&gt;
      a_checker.add_bin_ge_pre_action (agent process_bin_ge)&lt;br /&gt;
      a_checker.add_bin_gt_pre_action (agent process_bin_gt)&lt;br /&gt;
      a_checker.add_bin_le_pre_action (agent process_bin_le)&lt;br /&gt;
      a_checker.add_bin_lt_pre_action (agent process_bin_lt)&lt;br /&gt;
      a_checker.add_loop_pre_action (agent pre_process_loop)&lt;br /&gt;
      a_checker.add_loop_post_action (agent post_process_loop)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The complete source code of this rule is available in the [https://svn.eiffel.com/eiffelstudio/branches/eth/eve/Src/framework/code_analysis/rules/expressions/ca_self_comparison_rule.e SVN repository].&lt;br /&gt;
&lt;br /&gt;
== Example: Rule # 2: ''Unused argument'' ==&lt;br /&gt;
&lt;br /&gt;
The ''unused argument'' rule processes the ''feature'', ''body'', ''access id'', and ''converted expression'' AST nodes. The feature node is stored for the description and for ignoring ''deferred'' features. The body node is used to retrieve the arguments. The ''access id'' and ''converted expression'' nodes may represent used arguments, so the nodes are used to mark arguments as read. We register the ''pre'' actions for all the AST nodes as well as the ''post'' action for the ''body'' node in &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      a_checker.add_feature_pre_action (agent process_feature)&lt;br /&gt;
      a_checker.add_body_pre_action (agent process_body)&lt;br /&gt;
      a_checker.add_body_post_action (agent post_process_body)&lt;br /&gt;
      a_checker.add_access_id_pre_action (agent process_access_id)&lt;br /&gt;
      a_checker.add_converted_expr_pre_action (agent process_converted_expr)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On processing a feature we store the feature instance, which will be used later.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_feature (a_feature_as: FEATURE_AS)&lt;br /&gt;
    -- Sets the current feature.&lt;br /&gt;
  do&lt;br /&gt;
    current_feature := a_feature_as&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Before processing the body of a feature we store a list of all the argument names. This is however only done if the feature is a routine, if it has arguments, and if it is not external. In the code we need two nested loops since the arguments are grouped by type. For example, two consecutive &amp;lt;e&amp;gt;STRING&amp;lt;/e&amp;gt; arguments as in &amp;lt;e&amp;gt;feature print(first, second: STRING)&amp;lt;/e&amp;gt; are in one entry of &amp;lt;e&amp;gt;{BODY_AS}.arguments&amp;lt;/e&amp;gt;. This single entry is itself a list of arguments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_body (a_body_as: BODY_AS)&lt;br /&gt;
    -- Retrieves the arguments from `a_body_as'.&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    has_arguments := (a_body_as.arguments /= Void)&lt;br /&gt;
    create args_used.make (0)&lt;br /&gt;
    n_arguments := 0&lt;br /&gt;
    if&lt;br /&gt;
      attached a_body_as.as_routine as l_rout&lt;br /&gt;
      and then has_arguments&lt;br /&gt;
      and then not l_rout.is_external&lt;br /&gt;
    then&lt;br /&gt;
      routine_body := a_body_as&lt;br /&gt;
      create arg_names.make (0)&lt;br /&gt;
      across a_body_as.arguments as l_args loop&lt;br /&gt;
        from&lt;br /&gt;
          j := 1&lt;br /&gt;
        until&lt;br /&gt;
          j &amp;gt; l_args.item.id_list.count&lt;br /&gt;
        loop&lt;br /&gt;
          arg_names.extend (l_args.item.item_name (j))&lt;br /&gt;
          args_used.extend (False)&lt;br /&gt;
          n_arguments := n_arguments + 1&lt;br /&gt;
          j := j + 1&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
has_arguments: BOOLEAN&lt;br /&gt;
    -- Does current feature have arguments?&lt;br /&gt;
&lt;br /&gt;
current_feature: FEATURE_AS&lt;br /&gt;
    -- Currently checked feature.&lt;br /&gt;
&lt;br /&gt;
routine_body: BODY_AS&lt;br /&gt;
    -- Current routine body.&lt;br /&gt;
&lt;br /&gt;
n_arguments: INTEGER&lt;br /&gt;
    -- # arguments for current routine.&lt;br /&gt;
&lt;br /&gt;
arg_names: ARRAYED_LIST [STRING_32]&lt;br /&gt;
    -- Argument names of current routine.&lt;br /&gt;
&lt;br /&gt;
args_used: ARRAYED_LIST [BOOLEAN]&lt;br /&gt;
    -- Which argument has been used?&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both the nodes &amp;lt;e&amp;gt;{ACCESS_ID_AS}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{CONVERTED_EXPR_AS}&amp;lt;/e&amp;gt; may represent used arguments. &amp;lt;e&amp;gt;{ACCESS_ID_AS}&amp;lt;/e&amp;gt; is a usual variable usage, while &amp;lt;e&amp;gt;{CONVERTED_EXPR_AS}&amp;lt;/e&amp;gt; stands for an argument used in inline C code (the dollar sign syntax: &amp;lt;e&amp;gt;$arg&amp;lt;/e&amp;gt;). In both routines &amp;lt;e&amp;gt;check_arguments&amp;lt;/e&amp;gt; is called eventually, which updates the internal data structures of our rule class.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_access_id (a_aid: ACCESS_ID_AS)&lt;br /&gt;
    -- Checks if `a_aid' is an argument.&lt;br /&gt;
  do&lt;br /&gt;
    check_arguments (a_aid.feature_name.name_32)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_converted_expr (a_conv: CONVERTED_EXPR_AS)&lt;br /&gt;
    -- Checks if `a_conv' is an argument used in the&lt;br /&gt;
    -- form `$arg'.&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    if&lt;br /&gt;
      attached {ADDRESS_AS} a_conv.expr as l_address&lt;br /&gt;
      and then attached {FEAT_NAME_ID_AS} l_address.feature_name as l_id&lt;br /&gt;
    then&lt;br /&gt;
      check_arguments (l_id.feature_name.name_32)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
check_arguments (a_var_name: attached STRING_32)&lt;br /&gt;
    -- Mark an argument as used if it corresponds to `a_aid'.&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    from&lt;br /&gt;
      j := 1&lt;br /&gt;
    until&lt;br /&gt;
      j &amp;gt; n_arguments&lt;br /&gt;
    loop&lt;br /&gt;
      if not args_used [j] and then arg_names [j].is_equal (a_var_name) then&lt;br /&gt;
        args_used [j] := True&lt;br /&gt;
      end&lt;br /&gt;
      j := j + 1&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;post_process_body&amp;lt;/e&amp;gt; finally checks if there exist unused arguments. If this is the case then all the relevant variable names are stored in the rule violation. Also, the feature is stored (for the feature name). The location of the violation is set to the start of the routine body. No rule violation is issued if the feature is deferred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
post_process_body (a_body: BODY_AS)&lt;br /&gt;
    -- Adds a violation if the feature contains unused arguments.&lt;br /&gt;
  local&lt;br /&gt;
    l_violation: CA_RULE_VIOLATION&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    if&lt;br /&gt;
      a_body.content /= Void&lt;br /&gt;
      and then not current_feature.is_deferred&lt;br /&gt;
      and then has_arguments&lt;br /&gt;
      and then args_used.has (False)&lt;br /&gt;
    then&lt;br /&gt;
      create l_violation.make_with_rule (Current)&lt;br /&gt;
      l_violation.set_location (routine_body.start_location)&lt;br /&gt;
      l_violation.long_description_info.extend (current_feature)&lt;br /&gt;
      from&lt;br /&gt;
        j := 1&lt;br /&gt;
      until&lt;br /&gt;
        j &amp;gt; n_arguments&lt;br /&gt;
      loop&lt;br /&gt;
        if not args_used.at (j) then&lt;br /&gt;
          l_violation.long_description_info.extend (arg_names.at (j))&lt;br /&gt;
        end&lt;br /&gt;
        j := j + 1&lt;br /&gt;
      end&lt;br /&gt;
      violations.extend (l_violation)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All the information that was stored in the rule violation is used for the formatted description:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    a_formatter.add (ca_messages.unused_argument_violation_1)&lt;br /&gt;
    from&lt;br /&gt;
      j := 2&lt;br /&gt;
    until&lt;br /&gt;
      j &amp;gt; a_violation.long_description_info.count&lt;br /&gt;
    loop&lt;br /&gt;
      if j &amp;gt; 2 then a_formatter.add (&amp;quot;, &amp;quot;) end&lt;br /&gt;
      a_formatter.add (&amp;quot;'&amp;quot;)&lt;br /&gt;
      if attached {STRING_32} a_violation.long_description_info.at (j) as l_arg then&lt;br /&gt;
        a_formatter.add_local (l_arg)&lt;br /&gt;
      end&lt;br /&gt;
      a_formatter.add (&amp;quot;'&amp;quot;)&lt;br /&gt;
      j := j + 1&lt;br /&gt;
    end&lt;br /&gt;
    a_formatter.add (ca_messages.unused_argument_violation_2)&lt;br /&gt;
    if attached {FEATURE_AS} a_violation.long_description_info.first as l_feature then&lt;br /&gt;
      a_formatter.add_feature_name (l_feature.feature_name.name_32, a_violation.affected_class)&lt;br /&gt;
    end&lt;br /&gt;
    a_formatter.add (ca_messages.unused_argument_violation_3)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The complete source code of this rule is available in the [https://svn.eiffel.com/eiffelstudio/branches/eth/eve/Src/framework/code_analysis/rules/features/ca_unused_argument_rule.e SVN repository].&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15127</id>
		<title>CA Adding New Rules</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15127"/>
				<updated>2014-03-20T14:05:34Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: new name&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Command Line Usage|&amp;amp;lt;&amp;amp;lt; 5. Command Line Usage]] | [[User:Stefan/Code Analysis/Library Implementation|7. Library Implementation &amp;amp;gt;&amp;amp;gt;]] &amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
The Inspector Eiffel framework was designed with regard to the fact that '''adding new rules''' should be as simple and as fast as possible. Looking at the initial set of rules that were implemented, nearly all of them have an implementation of less than 200 lines of code. Many of them use even less than 100 lines of code. Rules that search the code for certain patterns (this applies to the vast majority of rules) are particularly simple to implement.&lt;br /&gt;
&lt;br /&gt;
This page shows you how to implement a rule in the form of a class. After you have written such a class you must add the rule to the list of rules. This list is populated in &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.make&amp;lt;/e&amp;gt;. There, just below the lines where all the other rules are added add a line like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;rules.extend (create {YOUR_RULE}.make)&amp;lt;/e&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;e&amp;gt;YOUR_RULE&amp;lt;/e&amp;gt; must be replaced by the name of your rule class and the creation procedure (&amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt;) must be adapted if necessary.&lt;br /&gt;
&lt;br /&gt;
== Standard Rules ==&lt;br /&gt;
&lt;br /&gt;
All rules must conform to &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. The class you implement for a rule is on one hand responsible for checking the rule and contains metadata about the rule (i. e. title, description) on the other hand. As of now, rules must moreover conform to either &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;CA_CFG_RULE&amp;lt;/e&amp;gt;, both of which are subtypes of &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. A large number of possible rules are ''standard rules'', no matter whether they are trivial or more complicated.&lt;br /&gt;
&lt;br /&gt;
All ''Standard rules'' are checked by iterating over the [http://en.wikipedia.org/wiki/Abstract_syntax_tree abstract syntax tree] (AST) of the class code. The developer who adds a new rule can very well ignore the details thereof. He needs to know however which AST nodes his rule needs to process. For each type of AST node you need to add an agent so your routine will be called during the iteration on the AST.&lt;br /&gt;
&lt;br /&gt;
To start implementing your rule you have basically two possibilities. (1) You start from scratch, implementing all deferred features of &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or (2) you use the following template.&lt;br /&gt;
&lt;br /&gt;
=== Standard Rule Template ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
class&lt;br /&gt;
  CA_YOUR_RULE&lt;br /&gt;
&lt;br /&gt;
inherit&lt;br /&gt;
  CA_STANDARD_RULE&lt;br /&gt;
&lt;br /&gt;
create&lt;br /&gt;
  make&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Initialization&lt;br /&gt;
&lt;br /&gt;
  make (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initialization for `Current'.&lt;br /&gt;
    do&lt;br /&gt;
      make_with_defaults&lt;br /&gt;
        -- This initializes the attributes to their default values:&lt;br /&gt;
        -- Severity = warning&lt;br /&gt;
        -- Default Severity Score = 50 (`severity score' can be changed by user)&lt;br /&gt;
        -- Rule enabled by default = True (`Rule enabled' can be changed by user)&lt;br /&gt;
        -- Only for system wide checks = False&lt;br /&gt;
        -- Checks library classes = True&lt;br /&gt;
        -- Checks nonlibrary classes = True&lt;br /&gt;
&lt;br /&gt;
        initialize_options (a_pref_manager)&lt;br /&gt;
&lt;br /&gt;
        -- TODO: Add your initialization here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  initialize_options (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initializes the rule preferences.&lt;br /&gt;
    local&lt;br /&gt;
      l_factory: BASIC_PREFERENCE_FACTORY&lt;br /&gt;
    do&lt;br /&gt;
      create l_factory&lt;br /&gt;
     &lt;br /&gt;
        -- TODO: Add the initialization of your custom preferences here.&lt;br /&gt;
        -- Example:&lt;br /&gt;
--    threshold := l_factory.new_integer_preference_value (a_pref_manager,&lt;br /&gt;
--      preference_namespace + &amp;quot;Threshold&amp;quot;,&lt;br /&gt;
--      30)  -- default value&lt;br /&gt;
--    min_local_name_length.set_default_value (&amp;quot;30&amp;quot;) -- default value, too&lt;br /&gt;
--    min_local_name_length.set_validation_agent (agent is_integer_string_within_bounds (?, 1, 1_000_000))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add agents for the features in section `Rule checking' here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Rule checking&lt;br /&gt;
&lt;br /&gt;
  -- TODO: Add the AST processing here.&lt;br /&gt;
&lt;br /&gt;
feature -- Properties&lt;br /&gt;
&lt;br /&gt;
  title: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the title of your rule here.&lt;br /&gt;
      Result := &amp;quot;(Your title)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- TODO: Add the ID of your rule here. Should be unique!&lt;br /&gt;
  id: STRING_32 = &amp;quot;(YourID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  description: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the rule description here.&lt;br /&gt;
      Result :=  &amp;quot;(Your description)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add a formatted description of a concrete violation of this rule here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let us have a closer look at the various parts of a rule class.&lt;br /&gt;
&lt;br /&gt;
=== Initialization ===&lt;br /&gt;
&lt;br /&gt;
Calling &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt; initializes the attributes to their default values and makes sure that the class invariant is true. If you want to set an attribute to a custom value you can do so by setting it after the call to &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The creation procedure from the template takes an argument of type &amp;lt;e&amp;gt;PREFERENCE_MANAGER&amp;lt;/e&amp;gt;. This is used for initializing preferences that are specific to your rule. Such preferences usually represent integral or boolean values. If you do ''not'' need any custom preferences then you can leave out the argument &amp;lt;e&amp;gt;a_pref_manager&amp;lt;/e&amp;gt; of &amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt; and you can remove the whole &amp;lt;e&amp;gt;initialize_options&amp;lt;/e&amp;gt; feature.&lt;br /&gt;
&lt;br /&gt;
=== AST Processing ===&lt;br /&gt;
&lt;br /&gt;
The main part of your rule implementation consists of checking the source code for rule violations. Say, for example, that you want to check &amp;lt;e&amp;gt;if&amp;lt;/e&amp;gt; instructions to have certain properties. Then you would add a feature like &amp;lt;e&amp;gt;process_if (a_if_ast: IF_AS)&amp;lt;/e&amp;gt; to the section ''Rule checking''. Also, you would need to modify the &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt; feature by adding the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;a_checker.add_if_pre_action (agent process_if)&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Of course you may register as many such agents as you want.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
The ''title'' and the ''description'' of the rule may be constant strings, they may also be localized strings. The ''rule ID'' must be unique among all rules. It should not contain spaces and should be reasonably short. The main rules that come with ''Code Analysis'' have IDs that are numbered from CA001 to CA999 (many of which are not used).&lt;br /&gt;
&lt;br /&gt;
=== Formatted Violation Description ===&lt;br /&gt;
&lt;br /&gt;
Your rule should be able to produce a formatted description of a concrete rule violation. This description is for example used in the Code Analysis tool panel of the GUI. There, class names and feature names are enabled for pick-and-drop. Variable names, numbers, and strings will be displayed in a nice way, too. In addition, this description is used in command line mode. In order to produce normal, unformatted text, use &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add&amp;lt;/e&amp;gt;. For adding formatted elements use features like &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_local&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_feature_name&amp;lt;/e&amp;gt; and similar.&lt;br /&gt;
&lt;br /&gt;
You should store all the data you need for this description (variables names, numbers, etc.) in &amp;lt;e&amp;gt;{CA_RULE_VIOLATION}.long_description_info&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;format_violation_description&amp;lt;/e&amp;gt; can then retrieve this data for the formatted output. Here is a simple example of producing a formatted description:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
a_formatter.add (&amp;quot;Feature &amp;quot;)&lt;br /&gt;
if attached {STRING_32} a_violation.long_description_info.first as l_feat_name then&lt;br /&gt;
  a_formatter.add_feature_name (l_feat_name, a_violation.affected_class)&lt;br /&gt;
end&lt;br /&gt;
a_formatter.add (&amp;quot; is very long.&amp;quot;)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== More Customized Rules ==&lt;br /&gt;
&lt;br /&gt;
For rules that do not fit into a simple AST visitor scheme you best inherit your rule from &amp;lt;e&amp;gt;{CA_STANDARD_RULE}&amp;lt;/e&amp;gt;, too. You can for example register agents that get called when a ''class'' or a ''feature'' is processed. Based on these agents you can perform your customized analysis on the classes and/or features. Using ''multiple inheritance'' or just aggregation it should hardly be a problem to include any functionality you need for your analysis.&lt;br /&gt;
&lt;br /&gt;
== Accessing Type Information ==&lt;br /&gt;
&lt;br /&gt;
The AST classes do not contain ''type information''. Suppose your rule processes function calls. Feature calls in the AST do not contain any information on the types, such as the type of the result.&lt;br /&gt;
&lt;br /&gt;
The code analysis framework however provides functionality to retrieve the type of AST nodes. Before the analyzer lets a class be analyzed by all the rules it computes the types of the AST nodes of a class. Hence this data will be available to your rule afterwards.&lt;br /&gt;
&lt;br /&gt;
While your rule is being checked you can retrieve the type of node &amp;lt;e&amp;gt;a_node&amp;lt;/e&amp;gt; from feature &amp;lt;e&amp;gt;a_feature&amp;lt;/e&amp;gt; by calling &amp;lt;e&amp;gt;current_context.node_type (a_node: AST_EIFFEL; a_feature: FEATURE_I)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;{CA_RULE}.current_context&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; and contains other information about current rule checking, too, such as the currently processed class or the matchlist for this class.&lt;br /&gt;
&lt;br /&gt;
== Accessing the Control Flow Graph ==&lt;br /&gt;
&lt;br /&gt;
Some kinds of static code analysis need and use the ''control flow graph'' of a program. The code analysis framework supports rules that use the control flow graph. If there is at least one such rule, the code analyzer computes the control flow graph of the procedures of the analyzed class before letting the ''rule'' check this class.&lt;br /&gt;
&lt;br /&gt;
=== Worklist Algorithms ===&lt;br /&gt;
&lt;br /&gt;
''Control flow graph rules'' iterate over the control flow graph. They do it using a ''worklist''—a list of CFG edges that still have to be processed. At the beginning, the worklist contains all edges of the control flow graph. The algorithm will pick edges from the worklist for processing in an arbitrary order. The iteration stops as soon as there are no more edges left in the worklist. How will the worklist get smaller? Each edge that is processed is removed from the worklist. After processing you will have to decide dynamically whether to add all the outgoing (or incoming, depending on the direction) edges to the worklist. Like this you can take the fact into account that some analyses need certain edges to be processed more than once (a fixed point iteration is such an example).&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
A control flow analysis may iterate in either direction. For a forward-directed analysis inherit your rule from &amp;lt;e&amp;gt;{CA_CFG_FORWARD_RULE}&amp;lt;/e&amp;gt;, for a backward analysis use &amp;lt;e&amp;gt;{CA_CFG_BACKWARD_RULE}&amp;lt;/e&amp;gt; instead. In either case you will then have to implement the following deferred features:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;initialize_processing (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; : This is called before a routine is processed using the worklist. Essentially you may use it to initialize and prepare all the data structures you will need during analysis.&lt;br /&gt;
; &amp;lt;e&amp;gt;visit_edge (a_from, a_to: attached CA_CFG_BASIC_BLOCK): BOOLEAN&amp;lt;/e&amp;gt; : This will be called when an edge is being visited. Here, you can put the analysis. If you let &amp;lt;e&amp;gt;Result = False&amp;lt;/e&amp;gt; then no further edges will be added to the worklist. If in contrary you let &amp;lt;e&amp;gt;Result = True&amp;lt;/e&amp;gt; then edges will be added to the worklist: In a ''forward'' analysis all the ''outgoing'' edges of the current one will be added; in a ''backward'' analysis all the ''incoming'' edges will be added.&lt;br /&gt;
&lt;br /&gt;
=== Non-Worklist algorithms ===&lt;br /&gt;
&lt;br /&gt;
If your control flow graph does not fit into the structure of an algorithm as described above you may directly inherit from &amp;lt;e&amp;gt;{CA_CFG_RULE}&amp;lt;/e&amp;gt; and implement the feature &amp;lt;e&amp;gt;process_cfg (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; (in addition to the features explained above). In this case you do not have to use a worklist; basically you can process the control flow graph in any way you want.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:CA_Cluster_Context_Menu.png&amp;diff=15121</id>
		<title>File:CA Cluster Context Menu.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:CA_Cluster_Context_Menu.png&amp;diff=15121"/>
				<updated>2014-03-20T13:55:42Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: Stefan uploaded a new version of &amp;amp;quot;File:CA Cluster Context Menu.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:CA_Class_Context_Menu.png&amp;diff=15120</id>
		<title>File:CA Class Context Menu.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:CA_Class_Context_Menu.png&amp;diff=15120"/>
				<updated>2014-03-20T13:55:12Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: Stefan uploaded a new version of &amp;amp;quot;File:CA Class Context Menu.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:CA_Analysis_Buttons.png&amp;diff=15119</id>
		<title>File:CA Analysis Buttons.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:CA_Analysis_Buttons.png&amp;diff=15119"/>
				<updated>2014-03-20T13:54:31Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: Stefan uploaded a new version of &amp;amp;quot;File:CA Analysis Buttons.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:CA_Sample_Results.png&amp;diff=15118</id>
		<title>File:CA Sample Results.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:CA_Sample_Results.png&amp;diff=15118"/>
				<updated>2014-03-20T13:53:48Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: Stefan uploaded a new version of &amp;amp;quot;File:CA Sample Results.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:CA_Preferences_Dialog.png&amp;diff=15117</id>
		<title>File:CA Preferences Dialog.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:CA_Preferences_Dialog.png&amp;diff=15117"/>
				<updated>2014-03-20T13:53:01Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: Stefan uploaded a new version of &amp;amp;quot;File:CA Preferences Dialog.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15116</id>
		<title>CA UI Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15116"/>
				<updated>2014-03-20T09:29:56Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: &amp;quot;EVE&amp;quot; -&amp;gt; &amp;quot;EiffelStudio&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Library Implementation|&amp;amp;lt;&amp;amp;lt; 7. Library Implementation]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
The classes of the graphical user interface of the code analyzer are all located in the ''interface'' cluster of EiffelStudio, in the subfolder ''graphical &amp;gt; tools &amp;gt; code_analysis''. Here is a short overview of what the single classes do:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL}&amp;lt;/e&amp;gt; : Represents the code analysis GUI tool. Contains the tool title and icon, otherwise not much interesting stuff.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL_PANEL}&amp;lt;/e&amp;gt; : The graphical panel for the code analysis tool. It contains buttons, labels, the rule violations table view, and other user interface elements.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; : 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_BENCH_HELPER}&amp;lt;/e&amp;gt; : A helper class for the integration of the code analysis tool. It contains shared instances of &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;, which are used by the GUI.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_SHOW_PREFERENCES_COMMAND}&amp;lt;/e&amp;gt; : The command is used by the ''Preferences'' button in the panel.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_FIX_EXECUTOR}&amp;lt;/e&amp;gt; : This class [[User:Stefan/Code Analysis/Using Analysis Results#Fixing Rule Violations|fixes]] a rule violation that has been found by the code analysis tool.&lt;br /&gt;
&lt;br /&gt;
These are roughly the class relations for the code analysis GUI:&lt;br /&gt;
[[File:CA GUI Diagram.png|thumb|center|650px|The most interesting class relations of the code analysis GUI.]]&lt;br /&gt;
&lt;br /&gt;
=== Caching ===&lt;br /&gt;
&lt;br /&gt;
It is a common case that GUI users run the code analyzer again after having made some changes to the code. We do not need to analyze the same unchanged code again and again. Therefore code analysis caches the results in memory. This only applies to the GUI mode.&lt;br /&gt;
&lt;br /&gt;
Code analysis uses cached results exactly in one case: when the whole system is analyzed and the previous analysis was on the whole system, too.&lt;br /&gt;
&lt;br /&gt;
The caching functionality is implemented in &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;. When the command for analyzing the system is executed, the timestamps of the last modification of the classes are stored in &amp;lt;e&amp;gt;analysis_timestamp : HASH_TABLE [INTEGER, CLASS_I]&amp;lt;/e&amp;gt; before the analysis. Note that the cached results (the rule violations) themselves are managed by &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt;. The only difference to a non-cached analysis is that the rule violations are not deleted by &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; before the next analysis. Then, in case the next command is also for analyzing the whole system, the current timestamps are compared to the stored timestamps. Any class that has been changed in the meantime will be analyzed again; for any unchanged class the rule violations are taken from the cache.&lt;br /&gt;
&lt;br /&gt;
=== Example Command: Analyze One Class ===&lt;br /&gt;
&lt;br /&gt;
We will now roughly go through the code that is executed on the GUI part when the user wants to analyze a single class. As mentioned in Chapter [[User:Stefan/Code Analysis/Running the Analyzer|Running the Analyzer]], this can be done using the class context menu or by dropping the class stone on the button ''Analyze Item''.&lt;br /&gt;
&lt;br /&gt;
In any case &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}.execute_with_stone&amp;lt;/e&amp;gt; is called, which delegates to &amp;lt;e&amp;gt;execute_with_stone_content&amp;lt;/e&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
execute_with_stone (a_stone: STONE)&lt;br /&gt;
    -- Execute with `a_stone'.&lt;br /&gt;
  do&lt;br /&gt;
    execute_with_stone_content (a_stone, Void)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
execute_with_stone_content (a_stone: STONE; a_content: SD_CONTENT)&lt;br /&gt;
    -- Execute with `a_stone'.&lt;br /&gt;
  local&lt;br /&gt;
    l_save_confirm: ES_DISCARDABLE_COMPILE_SAVE_FILES_PROMPT&lt;br /&gt;
    l_classes: DS_ARRAYED_LIST [CLASS_I]&lt;br /&gt;
  do&lt;br /&gt;
      -- Show the tool right from the start.&lt;br /&gt;
    show_ca_tool&lt;br /&gt;
&lt;br /&gt;
    if not eiffel_project.is_compiling then&lt;br /&gt;
      if window_manager.has_modified_windows then&lt;br /&gt;
        create l_classes.make_default&lt;br /&gt;
        window_manager.all_modified_classes.do_all (agent l_classes.force_last)&lt;br /&gt;
        create l_save_confirm.make (l_classes)&lt;br /&gt;
        l_save_confirm.set_button_action (l_save_confirm.dialog_buttons.yes_button, agent save_compile_and_analyze (a_stone))&lt;br /&gt;
        l_save_confirm.set_button_action (l_save_confirm.dialog_buttons.no_button, agent compile_and_analyze (a_stone))&lt;br /&gt;
        l_save_confirm.show_on_active_window&lt;br /&gt;
      else&lt;br /&gt;
        compile_and_analyze (a_stone)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there are modified, unsaved windows a save confirmation dialog is displayed. Eventually program flow passes on to &amp;lt;e&amp;gt;compile_and_analyze&amp;lt;/e&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
compile_and_analyze (a_stone: STONE)&lt;br /&gt;
    -- Compile project and perform analysis of stone `a_stone'.&lt;br /&gt;
  local&lt;br /&gt;
    l_helper: ES_CODE_ANALYSIS_BENCH_HELPER&lt;br /&gt;
    l_dialog: ES_INFORMATION_PROMPT&lt;br /&gt;
  do&lt;br /&gt;
      -- Compile the project and only analyze if the compilation was successful.&lt;br /&gt;
    eiffel_project.quick_melt (True, True, True)&lt;br /&gt;
    if eiffel_project.successful then&lt;br /&gt;
      create l_helper&lt;br /&gt;
      if l_helper.code_analyzer.is_running then&lt;br /&gt;
        create l_dialog.make_standard (ca_messages.already_running_long)&lt;br /&gt;
        l_dialog.show_on_active_window&lt;br /&gt;
      else&lt;br /&gt;
        perform_analysis (a_stone)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;eiffel_project.quick_melt&amp;lt;/e&amp;gt; starts the compilation. A successful compilation is required for code analysis; otherwise nothing is analyzed. After compilation has succeeded we check if code analysis is already running. If this is the case then a dialog is displayed. If on the other hand this last possible obstacle is not present we finally start analyzing by calling &amp;lt;e&amp;gt;perform_analysis&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
perform_analysis (a_stone: STONE)&lt;br /&gt;
    -- Analyze `a_stone' only.&lt;br /&gt;
  local&lt;br /&gt;
    l_helper: ES_CODE_ANALYSIS_BENCH_HELPER&lt;br /&gt;
    l_scope_label: EV_LABEL&lt;br /&gt;
  do&lt;br /&gt;
      -- For simplicity let us assume that `a_stone' does not&lt;br /&gt;
      -- correspond to the system or is equivalent to it.&lt;br /&gt;
    last_was_analyze_all := False&lt;br /&gt;
&lt;br /&gt;
    create l_helper&lt;br /&gt;
    code_analyzer := l_helper.code_analyzer&lt;br /&gt;
    code_analyzer.clear_classes_to_analyze&lt;br /&gt;
    code_analyzer.rule_violations.wipe_out&lt;br /&gt;
&lt;br /&gt;
    l_scope_label := ca_tool.panel.scope_label&lt;br /&gt;
&lt;br /&gt;
    if attached {CLASSC_STONE} a_stone as s then&lt;br /&gt;
      code_analyzer.add_class (s.class_i.config_class)&lt;br /&gt;
      l_scope_label.set_text (s.class_name)&lt;br /&gt;
      l_scope_label.set_foreground_color (create {EV_COLOR}.make_with_8_bit_rgb (140, 140, 255))&lt;br /&gt;
      l_scope_label.set_pebble (s)&lt;br /&gt;
      l_scope_label.set_pick_and_drop_mode&lt;br /&gt;
      l_scope_label.set_tooltip (ca_messages.class_scope_tooltip)&lt;br /&gt;
    elseif [...]&lt;br /&gt;
    [...]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    disable_tool_button&lt;br /&gt;
    window_manager.display_message (ca_messages.status_bar_running)&lt;br /&gt;
    code_analyzer.add_completed_action (agent analysis_completed)&lt;br /&gt;
    code_analyzer.analyze&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The code that deals with stones other than classes is omitted.)&lt;br /&gt;
&lt;br /&gt;
At the start of the routine the code analyzer instance is retrieved from the helper class. All classes that may have been addedbefore, are removed. All previous rule violations are removed as well. The if clause creates a stone for the ''Last Scope'' label in the graphical panel. Then, the button in the tool is disabled so that starting another analysis is prevented until the current one has completed. Finally, the analysis is started. As soon as the analysis has completed &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}.analysis_completed&amp;lt;/e&amp;gt; is called. In this procedure the rule violations (and possibly the exceptions) are retrieved from the code analyzer and displayed in the list in the tool panel.&lt;br /&gt;
&lt;br /&gt;
== Command-Line Interface ==&lt;br /&gt;
&lt;br /&gt;
The whole command-line functionality of the code analyzer is located in the class &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. It is located in the ''tty'' cluster of EiffelStudio. &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt; is invoked by &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the root class for the ''batch'' (command-line) version of EiffelStudio. In &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the invocation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
elseif option.is_equal (&amp;quot;-code-analysis&amp;quot;) then&lt;br /&gt;
  l_at_args := arguments_in_range (current_option + 1, argument_count)&lt;br /&gt;
  current_option := argument_count + 1&lt;br /&gt;
  create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any command-line arguments after ''-code-analysis'' are passed on to &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. This class, in its creation procedure, processes the arguments as described in [[User:Stefan/Code_Analysis/Command Line Usage|Command Line Usage]]. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure &amp;lt;e&amp;gt;execute&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; of course uses the ''code_analysis'' library and the previously described interface of &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;. After analysis a list of rule violations is output to the command-line. In the code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
across l_code_analyzer.rule_violations as l_vlist loop&lt;br /&gt;
  if not l_vlist.item.is_empty then&lt;br /&gt;
    l_has_violations := True&lt;br /&gt;
      -- Always sort the rule violations by the class they are referring to.&lt;br /&gt;
    output_window.add (ca_messages.cmd_class + l_vlist.key.name + &amp;quot;':%N&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting.&lt;br /&gt;
    across l_vlist.item as ic loop&lt;br /&gt;
      l_rule_name := ic.item.rule.title&lt;br /&gt;
      l_rule_id := ic.item.rule.id&lt;br /&gt;
      if attached ic.item.location as l_loc then&lt;br /&gt;
        l_line := ic.item.location.line.out&lt;br /&gt;
        l_col := ic.item.location.column.out&lt;br /&gt;
        output_window.add (&amp;quot;  (&amp;quot; + l_line + &amp;quot;:&amp;quot; + l_col + &amp;quot;): &amp;quot;&lt;br /&gt;
          + l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      else -- No location attached. Print without location.&lt;br /&gt;
        output_window.add (&amp;quot;  &amp;quot;	+ l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      ic.item.format_violation_description (output_window)&lt;br /&gt;
      output_window.add (&amp;quot;%N&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not l_has_violations then output_window.add (ca_messages.no_issues + &amp;quot;%N&amp;quot;) end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15115</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15115"/>
				<updated>2014-03-20T09:28:38Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: &amp;quot;EVE&amp;quot; -&amp;gt; &amp;quot;EiffelStudio&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] | [[User:Stefan/Code Analysis/UI Implementation|8. UI Implementation &amp;amp;gt; &amp;amp;gt;]]&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the EiffelStudio source:&lt;br /&gt;
# The framework—by far the largest part, with the rule checking, the rules, the control flow graph functionality, and more—is represented as a ''library'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of EiffelStudio;&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of EiffelStudio.&lt;br /&gt;
&lt;br /&gt;
The whole '''code analysis framework''' is located in the '''library ''code_analysis'''''.&lt;br /&gt;
&lt;br /&gt;
== Class Relations ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows an overview of the relations between the classes of the code analysis framework. All classes are located in the ''code_analysis'' library except for &amp;lt;e&amp;gt;CLASS_C&amp;lt;/e&amp;gt; (EiffelStudio), &amp;lt;e&amp;gt;ROTA_TIMED_TASK_I&amp;lt;/e&amp;gt; (''ecosystem'' cluster), &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; (command-line interface), and &amp;lt;e&amp;gt;ES_CODE_ANALYSIS_BENCH_HELPER&amp;lt;/e&amp;gt; (GUI).&lt;br /&gt;
&lt;br /&gt;
[[File:CA Framework Diagram.png|thumb|center|800px|The most interesting classes of the code analysis framework.]]&lt;br /&gt;
&lt;br /&gt;
== Interface ==&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Rule Checking ==&lt;br /&gt;
&lt;br /&gt;
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'', &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;. In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt; this task (&amp;lt;e&amp;gt;l_task&amp;lt;/e&amp;gt;) is invoked as follows:&lt;br /&gt;
&lt;br /&gt;
=== In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed)&lt;br /&gt;
l_task.set_output_actions (output_actions)&lt;br /&gt;
rota.run_task (l_task)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; essentially runs the whole analysis. Like all other conformants to &amp;lt;e&amp;gt;{ROTA_TASK_I}&amp;lt;/e&amp;gt; this class executes a series of ''steps'' between which the user interface gets some time to process its events. In &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; each step analyses one class. This means that a class is checked by ''all'' the rules for violations. The following code does that:&lt;br /&gt;
&lt;br /&gt;
=== From &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
step&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
  do&lt;br /&gt;
    if has_next_step then&lt;br /&gt;
        -- Gather type information&lt;br /&gt;
      type_recorder.clear&lt;br /&gt;
      type_recorder.analyze_class (classes.item)&lt;br /&gt;
      context.set_node_types (type_recorder.node_types)&lt;br /&gt;
      context.set_checking_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      across rules as l_rules loop&lt;br /&gt;
          -- If rule is non-standard then it will not be checked by l_rules_checker.&lt;br /&gt;
          -- We will have the rule check the current class here:&lt;br /&gt;
        if&lt;br /&gt;
          l_rules.item.is_enabled.value&lt;br /&gt;
          and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule&lt;br /&gt;
        then&lt;br /&gt;
          l_cfg_rule.check_class (classes.item)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
        -- Status output.&lt;br /&gt;
      if output_actions /= Void then&lt;br /&gt;
        output_actions.call ([ca_messages.analyzing_class (classes.item.name)])&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      rules_checker.run_on_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      classes.forth&lt;br /&gt;
      has_next_step := not classes.after&lt;br /&gt;
      if not has_next_step then&lt;br /&gt;
        completed_action.call ([exceptions])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  rescue&lt;br /&gt;
      -- Instant error output.&lt;br /&gt;
    if output_actions /= Void then&lt;br /&gt;
      output_actions.call ([ca_messages.error_on_class (classes.item.name)])&lt;br /&gt;
    end&lt;br /&gt;
    exceptions.extend ([exception_manager.last_exception, classes.item])&lt;br /&gt;
      -- Jump to the next class.&lt;br /&gt;
    classes.forth&lt;br /&gt;
    has_next_step := not classes.after&lt;br /&gt;
    if not has_next_step then&lt;br /&gt;
      completed_action.call ([exceptions])&lt;br /&gt;
    end&lt;br /&gt;
    retry&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;type_recorder&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_AST_TYPE_RECORDER}&amp;lt;/e&amp;gt;. 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. &amp;lt;e&amp;gt;context&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;e&amp;gt;across&amp;lt;/e&amp;gt; loop only checks ''control flow graph rules''. All the ''standard'' rules are checked by the line &amp;lt;e&amp;gt;rules_checker.run_on_class (classes.item)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;rules_checker&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt;. This is the class where each rule must register the AST nodes the rule visits. &amp;lt;e&amp;gt;run_on_class&amp;lt;/e&amp;gt; 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. &amp;lt;e&amp;gt;step&amp;lt;/e&amp;gt; is executed repeatedly until there are no classes left to analyze.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;e&amp;gt;rescue&amp;lt;/e&amp;gt; clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.&lt;br /&gt;
&lt;br /&gt;
=== Checking ''Standard'' Rules ===&lt;br /&gt;
&lt;br /&gt;
The relatively large class &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; is responsible for checking ''standard rules''. It does this in a straightforward way. It is a subclass of &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt;, a realization of a visitor on the AST.&lt;br /&gt;
&lt;br /&gt;
Rules can register their actions with &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; by calling a procedure like &amp;lt;e&amp;gt;add_bin_lt_pre_action (a_action: attached PROCEDURE [ANY, TUPLE [BIN_LT_AS]])&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&amp;lt;/e&amp;gt;. These &amp;quot;pre&amp;quot; and &amp;quot;post&amp;quot; actions exist for many other types of AST nodes as well. All the registered actions are stored in &amp;lt;e&amp;gt;ACTION_SEQUENCE&amp;lt;/e&amp;gt; variables:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
if_pre_actions, if_post_actions: ACTION_SEQUENCE [TUPLE [IF_AS]]&lt;br /&gt;
&lt;br /&gt;
add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&lt;br /&gt;
  do&lt;br /&gt;
    if_post_actions.extend (a_action)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding visitor procedures are redefined. This is done is the following way:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_if_as (a_if: IF_AS)&lt;br /&gt;
  do&lt;br /&gt;
    if_pre_actions.call ([a_if])&lt;br /&gt;
    Precursor (a_if)&lt;br /&gt;
    if_post_actions.call ([a_if])&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the actual iteration over the AST is done in the ancestor we need only very little code to analyze a class:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {CA_RULE_CHECKING_TASK} -- Execution Commands&lt;br /&gt;
&lt;br /&gt;
  run_on_class (a_class_to_check: CLASS_C)&lt;br /&gt;
      -- Check all rules that have added their agents.&lt;br /&gt;
    local&lt;br /&gt;
      l_ast: CLASS_AS&lt;br /&gt;
    do&lt;br /&gt;
      last_run_successful := False&lt;br /&gt;
      l_ast := a_class_to_check.ast&lt;br /&gt;
      class_pre_actions.call ([l_ast])&lt;br /&gt;
      process_class_as (l_ast)&lt;br /&gt;
      class_post_actions.call ([l_ast])&lt;br /&gt;
      last_run_successful := True&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code analyzes a class for all active ''standard'' rules. &amp;lt;e&amp;gt;class_pre_actions&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;class_post_actions&amp;lt;/e&amp;gt; are action sequences that are identical to those for the AST nodes. &amp;lt;e&amp;gt;process_class_as&amp;lt;/e&amp;gt;, which is implemented in &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt; will recursively visit all relevant AST nodes and execute their action sequences.&lt;br /&gt;
&lt;br /&gt;
== Example: Rule # 71: ''Self-comparison'' ==&lt;br /&gt;
&lt;br /&gt;
We will go through the implementation of rule # 71 (''Self-comparison'') in detail.&lt;br /&gt;
&lt;br /&gt;
The heart of this implementation lies in the feature &amp;lt;e&amp;gt;analyze_self&amp;lt;/e&amp;gt;. There it is tested whether a binary expression is s self-comparison. &amp;lt;e&amp;gt;is_self&amp;lt;/e&amp;gt;, a &amp;lt;e&amp;gt;BOOLEAN&amp;lt;/e&amp;gt; attribute, is set to true if and only if the argument is a comparison between two identical variables.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
analyze_self (a_bin: attached BINARY_AS)&lt;br /&gt;
    -- Is `a_bin' a self-comparison?&lt;br /&gt;
  do&lt;br /&gt;
    is_self := False&lt;br /&gt;
&lt;br /&gt;
    if&lt;br /&gt;
      attached {EXPR_CALL_AS} a_bin.left as l_e1&lt;br /&gt;
      and then attached {ACCESS_ID_AS} l_e1.call as l_l&lt;br /&gt;
      and then attached {EXPR_CALL_AS} a_bin.right as l_e2&lt;br /&gt;
      and then attached {ACCESS_ID_AS} l_e2.call as l_r&lt;br /&gt;
    then&lt;br /&gt;
      is_self := l_l.feature_name.is_equal (l_r.feature_name)&lt;br /&gt;
      self_name := l_l.access_name_32&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
is_self: BOOLEAN&lt;br /&gt;
    -- Is `a_bin' from last call to `analyze_self' a self-comparison?&lt;br /&gt;
&lt;br /&gt;
self_name: detachable STRING_32&lt;br /&gt;
    -- Name of the self-compared variable.&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both sides of the comparison, &amp;lt;e&amp;gt;a_bin.left&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;a_bin.right&amp;lt;/e&amp;gt;, are tested to have the types that indicate that they are variable or feature accesses. If the tests succeed then &amp;lt;e&amp;gt;is_self&amp;lt;/e&amp;gt; is set according to the equality of the two feature names. Then the name is stored in an internal attribute.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;analyze_self&amp;lt;/e&amp;gt; is used in &amp;lt;e&amp;gt;process_comparison&amp;lt;/e&amp;gt;, which creates a rule violation if a self-comparison was detected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_comparison (a_comparison: BINARY_AS)&lt;br /&gt;
    -- Checks `a_comparison' for rule violations.&lt;br /&gt;
  local&lt;br /&gt;
    l_viol: CA_RULE_VIOLATION&lt;br /&gt;
  do&lt;br /&gt;
    if not in_loop then&lt;br /&gt;
      analyze_self (a_comparison)&lt;br /&gt;
      if is_self then&lt;br /&gt;
        create l_viol.make_with_rule (Current)&lt;br /&gt;
        l_viol.set_location (a_comparison.start_location)&lt;br /&gt;
        l_viol.long_description_info.extend (self_name)&lt;br /&gt;
        violations.extend (l_viol)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First we check that we are not dealing with a loop condition. Self-comparisons in loop conditions are more dangerous and need special treatment (see below). For the rule violation, we set the location to the start location of the binary comparison. We add the variable or feature name to the violation.&lt;br /&gt;
&lt;br /&gt;
Different kinds of comparisons also have different types in the AST. That is why in an AST iterator they are processed independently. Thus, we need to add some delegation to each of the actions that are called when processing a comparison.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_bin_eq (a_bin_eq: BIN_EQ_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_eq)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_ge (a_bin_ge: BIN_GE_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_ge)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_gt (a_bin_gt: BIN_GT_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_gt)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_le (a_bin_le: BIN_LE_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_le)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_lt (a_bin_lt: BIN_LT_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_lt)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the case that a loop condition is a self-comparison, the loop is either never entered or it is never exited. The last case is more severe; the first case only arises with an equality comparison. For this reason we analyze loop conditions separately. If we find such a violation we set &amp;lt;e&amp;gt;in_loop&amp;lt;/e&amp;gt; to &amp;lt;e&amp;gt;True&amp;lt;/e&amp;gt; so that any further self-comparisons are ignored until we have left the loop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
pre_process_loop (a_loop: LOOP_AS)&lt;br /&gt;
    -- Checking a loop `a_loop' for self-comparisons needs more work. If the until expression&lt;br /&gt;
    -- is a self-comparison that does not compare for equality then the loop will&lt;br /&gt;
    -- not terminate, which is more severe consequence compared to other self-comparisons.&lt;br /&gt;
  local&lt;br /&gt;
    l_viol: CA_RULE_VIOLATION&lt;br /&gt;
  do&lt;br /&gt;
    if attached {BINARY_AS} a_loop.stop as l_bin then&lt;br /&gt;
    analyze_self (l_bin)&lt;br /&gt;
    if is_self then&lt;br /&gt;
      create l_viol.make_with_rule (Current)&lt;br /&gt;
      l_viol.set_location (a_loop.stop.start_location)&lt;br /&gt;
      l_viol.long_description_info.extend (self_name)&lt;br /&gt;
      if not attached {BIN_EQ_AS} l_bin then&lt;br /&gt;
          -- It is only a dangerous loop stop condition if we do not have&lt;br /&gt;
          -- an equality comparison.&lt;br /&gt;
        l_viol.long_description_info.extend (&amp;quot;loop_stop&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      violations.extend (l_viol)&lt;br /&gt;
      in_loop := True&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;format_violation_description&amp;lt;/e&amp;gt;, which is declared in &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt; as &amp;lt;e&amp;gt;deferred&amp;lt;/e&amp;gt;, must be implemented. Here, together with a predefined localized text, we mention the name of the self-compared variable. If the self-comparison is located in a loop stop condition we add an additional warning text.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
  local&lt;br /&gt;
    l_info: LINKED_LIST [ANY]&lt;br /&gt;
  do&lt;br /&gt;
    l_info := a_violation.long_description_info&lt;br /&gt;
    a_formatter.add (&amp;quot;'&amp;quot;)&lt;br /&gt;
    if l_info.count &amp;gt;= 1 and then attached {STRING_32} l_info.first as l_name then&lt;br /&gt;
      a_formatter.add_local (l_name)&lt;br /&gt;
    end&lt;br /&gt;
    a_formatter.add (ca_messages.self_comparison_violation_1)&lt;br /&gt;
&lt;br /&gt;
    l_info.compare_objects&lt;br /&gt;
    if l_info.has (&amp;quot;loop_stop&amp;quot;) then&lt;br /&gt;
        -- Dangerous loop stop condition.&lt;br /&gt;
      a_formatter.add (ca_messages.self_comparison_violation_2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we must implement the usual properties.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
title: STRING_32&lt;br /&gt;
  do&lt;br /&gt;
    Result := ca_names.self_comparison_title&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
id: STRING_32 = &amp;quot;CA071&amp;quot;&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
&lt;br /&gt;
description: STRING_32&lt;br /&gt;
  do&lt;br /&gt;
    Result :=  ca_names.self_comparison_description&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, in the initialization we use the default settings, which can be set by calling &amp;lt;e&amp;gt;{CA_RULE}.make_with_defaults&amp;lt;/e&amp;gt;. To the default severity score we assign a custom value. In &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt; we must add all the agents for processing the loop and comparison nodes of the AST.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {NONE} -- Initialization&lt;br /&gt;
&lt;br /&gt;
  make&lt;br /&gt;
      -- Initialization.&lt;br /&gt;
    do&lt;br /&gt;
      make_with_defaults&lt;br /&gt;
      default_severity_score := 70&lt;br /&gt;
		  end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      a_checker.add_bin_eq_pre_action (agent process_bin_eq)&lt;br /&gt;
      a_checker.add_bin_ge_pre_action (agent process_bin_ge)&lt;br /&gt;
      a_checker.add_bin_gt_pre_action (agent process_bin_gt)&lt;br /&gt;
      a_checker.add_bin_le_pre_action (agent process_bin_le)&lt;br /&gt;
      a_checker.add_bin_lt_pre_action (agent process_bin_lt)&lt;br /&gt;
      a_checker.add_loop_pre_action (agent pre_process_loop)&lt;br /&gt;
      a_checker.add_loop_post_action (agent post_process_loop)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The complete source code of this rule is available in the [https://svn.eiffel.com/eiffelstudio/branches/eth/eve/Src/framework/code_analysis/rules/expressions/ca_self_comparison_rule.e SVN repository].&lt;br /&gt;
&lt;br /&gt;
== Example: Rule # 2: ''Unused argument'' ==&lt;br /&gt;
&lt;br /&gt;
The ''unused argument'' rule processes the ''feature'', ''body'', ''access id'', and ''converted expression'' AST nodes. The feature node is stored for the description and for ignoring ''deferred'' features. The body node is used to retrieve the arguments. The ''access id'' and ''converted expression'' nodes may represent used arguments, so the nodes are used to mark arguments as read. We register the ''pre'' actions for all the AST nodes as well as the ''post'' action for the ''body'' node in &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      a_checker.add_feature_pre_action (agent process_feature)&lt;br /&gt;
      a_checker.add_body_pre_action (agent process_body)&lt;br /&gt;
      a_checker.add_body_post_action (agent post_process_body)&lt;br /&gt;
      a_checker.add_access_id_pre_action (agent process_access_id)&lt;br /&gt;
      a_checker.add_converted_expr_pre_action (agent process_converted_expr)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On processing a feature we store the feature instance, which will be used later.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_feature (a_feature_as: FEATURE_AS)&lt;br /&gt;
    -- Sets the current feature.&lt;br /&gt;
  do&lt;br /&gt;
    current_feature := a_feature_as&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Before processing the body of a feature we store a list of all the argument names. This is however only done if the feature is a routine, if it has arguments, and if it is not external. In the code we need two nested loops since the arguments are grouped by type. For example, two consecutive &amp;lt;e&amp;gt;STRING&amp;lt;/e&amp;gt; arguments as in &amp;lt;e&amp;gt;feature print(first, second: STRING)&amp;lt;/e&amp;gt; are in one entry of &amp;lt;e&amp;gt;{BODY_AS}.arguments&amp;lt;/e&amp;gt;. This single entry is itself a list of arguments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_body (a_body_as: BODY_AS)&lt;br /&gt;
    -- Retrieves the arguments from `a_body_as'.&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    has_arguments := (a_body_as.arguments /= Void)&lt;br /&gt;
    create args_used.make (0)&lt;br /&gt;
    n_arguments := 0&lt;br /&gt;
    if&lt;br /&gt;
      attached a_body_as.as_routine as l_rout&lt;br /&gt;
      and then has_arguments&lt;br /&gt;
      and then not l_rout.is_external&lt;br /&gt;
    then&lt;br /&gt;
      routine_body := a_body_as&lt;br /&gt;
      create arg_names.make (0)&lt;br /&gt;
      across a_body_as.arguments as l_args loop&lt;br /&gt;
        from&lt;br /&gt;
          j := 1&lt;br /&gt;
        until&lt;br /&gt;
          j &amp;gt; l_args.item.id_list.count&lt;br /&gt;
        loop&lt;br /&gt;
          arg_names.extend (l_args.item.item_name (j))&lt;br /&gt;
          args_used.extend (False)&lt;br /&gt;
          n_arguments := n_arguments + 1&lt;br /&gt;
          j := j + 1&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
has_arguments: BOOLEAN&lt;br /&gt;
    -- Does current feature have arguments?&lt;br /&gt;
&lt;br /&gt;
current_feature: FEATURE_AS&lt;br /&gt;
    -- Currently checked feature.&lt;br /&gt;
&lt;br /&gt;
routine_body: BODY_AS&lt;br /&gt;
    -- Current routine body.&lt;br /&gt;
&lt;br /&gt;
n_arguments: INTEGER&lt;br /&gt;
    -- # arguments for current routine.&lt;br /&gt;
&lt;br /&gt;
arg_names: ARRAYED_LIST [STRING_32]&lt;br /&gt;
    -- Argument names of current routine.&lt;br /&gt;
&lt;br /&gt;
args_used: ARRAYED_LIST [BOOLEAN]&lt;br /&gt;
    -- Which argument has been used?&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both the nodes &amp;lt;e&amp;gt;{ACCESS_ID_AS}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{CONVERTED_EXPR_AS}&amp;lt;/e&amp;gt; may represent used arguments. &amp;lt;e&amp;gt;{ACCESS_ID_AS}&amp;lt;/e&amp;gt; is a usual variable usage, while &amp;lt;e&amp;gt;{CONVERTED_EXPR_AS}&amp;lt;/e&amp;gt; stands for an argument used in inline C code (the dollar sign syntax: &amp;lt;e&amp;gt;$arg&amp;lt;/e&amp;gt;). In both routines &amp;lt;e&amp;gt;check_arguments&amp;lt;/e&amp;gt; is called eventually, which updates the internal data structures of our rule class.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_access_id (a_aid: ACCESS_ID_AS)&lt;br /&gt;
    -- Checks if `a_aid' is an argument.&lt;br /&gt;
  do&lt;br /&gt;
    check_arguments (a_aid.feature_name.name_32)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_converted_expr (a_conv: CONVERTED_EXPR_AS)&lt;br /&gt;
    -- Checks if `a_conv' is an argument used in the&lt;br /&gt;
    -- form `$arg'.&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    if&lt;br /&gt;
      attached {ADDRESS_AS} a_conv.expr as l_address&lt;br /&gt;
      and then attached {FEAT_NAME_ID_AS} l_address.feature_name as l_id&lt;br /&gt;
    then&lt;br /&gt;
      check_arguments (l_id.feature_name.name_32)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
check_arguments (a_var_name: attached STRING_32)&lt;br /&gt;
    -- Mark an argument as used if it corresponds to `a_aid'.&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    from&lt;br /&gt;
      j := 1&lt;br /&gt;
    until&lt;br /&gt;
      j &amp;gt; n_arguments&lt;br /&gt;
    loop&lt;br /&gt;
      if not args_used [j] and then arg_names [j].is_equal (a_var_name) then&lt;br /&gt;
        args_used [j] := True&lt;br /&gt;
      end&lt;br /&gt;
      j := j + 1&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;post_process_body&amp;lt;/e&amp;gt; finally checks if there exist unused arguments. If this is the case then all the relevant variable names are stored in the rule violation. Also, the feature is stored (for the feature name). The location of the violation is set to the start of the routine body. No rule violation is issued if the feature is deferred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
post_process_body (a_body: BODY_AS)&lt;br /&gt;
    -- Adds a violation if the feature contains unused arguments.&lt;br /&gt;
  local&lt;br /&gt;
    l_violation: CA_RULE_VIOLATION&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    if&lt;br /&gt;
      a_body.content /= Void&lt;br /&gt;
      and then not current_feature.is_deferred&lt;br /&gt;
      and then has_arguments&lt;br /&gt;
      and then args_used.has (False)&lt;br /&gt;
    then&lt;br /&gt;
      create l_violation.make_with_rule (Current)&lt;br /&gt;
      l_violation.set_location (routine_body.start_location)&lt;br /&gt;
      l_violation.long_description_info.extend (current_feature)&lt;br /&gt;
      from&lt;br /&gt;
        j := 1&lt;br /&gt;
      until&lt;br /&gt;
        j &amp;gt; n_arguments&lt;br /&gt;
      loop&lt;br /&gt;
        if not args_used.at (j) then&lt;br /&gt;
          l_violation.long_description_info.extend (arg_names.at (j))&lt;br /&gt;
        end&lt;br /&gt;
        j := j + 1&lt;br /&gt;
      end&lt;br /&gt;
      violations.extend (l_violation)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All the information that was stored in the rule violation is used for the formatted description:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    a_formatter.add (ca_messages.unused_argument_violation_1)&lt;br /&gt;
    from&lt;br /&gt;
      j := 2&lt;br /&gt;
    until&lt;br /&gt;
      j &amp;gt; a_violation.long_description_info.count&lt;br /&gt;
    loop&lt;br /&gt;
      if j &amp;gt; 2 then a_formatter.add (&amp;quot;, &amp;quot;) end&lt;br /&gt;
      a_formatter.add (&amp;quot;'&amp;quot;)&lt;br /&gt;
      if attached {STRING_32} a_violation.long_description_info.at (j) as l_arg then&lt;br /&gt;
        a_formatter.add_local (l_arg)&lt;br /&gt;
      end&lt;br /&gt;
      a_formatter.add (&amp;quot;'&amp;quot;)&lt;br /&gt;
      j := j + 1&lt;br /&gt;
    end&lt;br /&gt;
    a_formatter.add (ca_messages.unused_argument_violation_2)&lt;br /&gt;
    if attached {FEATURE_AS} a_violation.long_description_info.first as l_feature then&lt;br /&gt;
      a_formatter.add_feature_name (l_feature.feature_name.name_32, a_violation.affected_class)&lt;br /&gt;
    end&lt;br /&gt;
    a_formatter.add (ca_messages.unused_argument_violation_3)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The complete source code of this rule is available in the [https://svn.eiffel.com/eiffelstudio/branches/eth/eve/Src/framework/code_analysis/rules/features/ca_unused_argument_rule.e SVN repository].&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15112</id>
		<title>CA Adding New Rules</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15112"/>
				<updated>2014-03-13T11:48:14Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* Non-worklist algorithms */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Command Line Usage|&amp;amp;lt;&amp;amp;lt; 5. Command Line Usage]] | [[User:Stefan/Code Analysis/Library Implementation|7. Library Implementation &amp;amp;gt;&amp;amp;gt;]] &amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
The Code Analysis framework was designed with regard to the fact that '''adding new rules''' should be as simple and as fast as possible. Looking at the initial set of rules that were implemented, nearly all of them have an implementation of less than 200 lines of code. Many of them use even less than 100 lines of code. Rules that search the code for certain patterns (this applies to the vast majority of rules) are particularly simple to implement.&lt;br /&gt;
&lt;br /&gt;
This page shows you how to implement a rule in the form of a class. After you have written such a class you must add the rule to the list of rules. This list is populated in &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.make&amp;lt;/e&amp;gt;. There, just below the lines where all the other rules are added add a line like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;rules.extend (create {YOUR_RULE}.make)&amp;lt;/e&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;e&amp;gt;YOUR_RULE&amp;lt;/e&amp;gt; must be replaced by the name of your rule class and the creation procedure (&amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt;) must be adapted if necessary.&lt;br /&gt;
&lt;br /&gt;
== Standard Rules ==&lt;br /&gt;
&lt;br /&gt;
All rules must conform to &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. The class you implement for a rule is on one hand responsible for checking the rule and contains metadata about the rule (i. e. title, description) on the other hand. As of now, rules must moreover conform to either &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;CA_CFG_RULE&amp;lt;/e&amp;gt;, both of which are subtypes of &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. A large number of possible rules are ''standard rules'', no matter whether they are trivial or more complicated.&lt;br /&gt;
&lt;br /&gt;
All ''Standard rules'' are checked by iterating over the [http://en.wikipedia.org/wiki/Abstract_syntax_tree abstract syntax tree] (AST) of the class code. The developer who adds a new rule can very well ignore the details thereof. He needs to know however which AST nodes his rule needs to process. For each type of AST node you need to add an agent so your routine will be called during the iteration on the AST.&lt;br /&gt;
&lt;br /&gt;
To start implementing your rule you have basically two possibilities. (1) You start from scratch, implementing all deferred features of &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or (2) you use the following template.&lt;br /&gt;
&lt;br /&gt;
=== Standard Rule Template ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
class&lt;br /&gt;
  CA_YOUR_RULE&lt;br /&gt;
&lt;br /&gt;
inherit&lt;br /&gt;
  CA_STANDARD_RULE&lt;br /&gt;
&lt;br /&gt;
create&lt;br /&gt;
  make&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Initialization&lt;br /&gt;
&lt;br /&gt;
  make (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initialization for `Current'.&lt;br /&gt;
    do&lt;br /&gt;
      make_with_defaults&lt;br /&gt;
        -- This initializes the attributes to their default values:&lt;br /&gt;
        -- Severity = warning&lt;br /&gt;
        -- Default Severity Score = 50 (`severity score' can be changed by user)&lt;br /&gt;
        -- Rule enabled by default = True (`Rule enabled' can be changed by user)&lt;br /&gt;
        -- Only for system wide checks = False&lt;br /&gt;
        -- Checks library classes = True&lt;br /&gt;
        -- Checks nonlibrary classes = True&lt;br /&gt;
&lt;br /&gt;
        initialize_options (a_pref_manager)&lt;br /&gt;
&lt;br /&gt;
        -- TODO: Add your initialization here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  initialize_options (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initializes the rule preferences.&lt;br /&gt;
    local&lt;br /&gt;
      l_factory: BASIC_PREFERENCE_FACTORY&lt;br /&gt;
    do&lt;br /&gt;
      create l_factory&lt;br /&gt;
     &lt;br /&gt;
        -- TODO: Add the initialization of your custom preferences here.&lt;br /&gt;
        -- Example:&lt;br /&gt;
--    threshold := l_factory.new_integer_preference_value (a_pref_manager,&lt;br /&gt;
--      preference_namespace + &amp;quot;Threshold&amp;quot;,&lt;br /&gt;
--      30)  -- default value&lt;br /&gt;
--    min_local_name_length.set_default_value (&amp;quot;30&amp;quot;) -- default value, too&lt;br /&gt;
--    min_local_name_length.set_validation_agent (agent is_integer_string_within_bounds (?, 1, 1_000_000))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add agents for the features in section `Rule checking' here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Rule checking&lt;br /&gt;
&lt;br /&gt;
  -- TODO: Add the AST processing here.&lt;br /&gt;
&lt;br /&gt;
feature -- Properties&lt;br /&gt;
&lt;br /&gt;
  title: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the title of your rule here.&lt;br /&gt;
      Result := &amp;quot;(Your title)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- TODO: Add the ID of your rule here. Should be unique!&lt;br /&gt;
  id: STRING_32 = &amp;quot;(YourID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  description: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the rule description here.&lt;br /&gt;
      Result :=  &amp;quot;(Your description)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add a formatted description of a concrete violation of this rule here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let us have a closer look at the various parts of a rule class.&lt;br /&gt;
&lt;br /&gt;
=== Initialization ===&lt;br /&gt;
&lt;br /&gt;
Calling &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt; initializes the attributes to their default values and makes sure that the class invariant is true. If you want to set an attribute to a custom value you can do so by setting it after the call to &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The creation procedure from the template takes an argument of type &amp;lt;e&amp;gt;PREFERENCE_MANAGER&amp;lt;/e&amp;gt;. This is used for initializing preferences that are specific to your rule. Such preferences usually represent integral or boolean values. If you do ''not'' need any custom preferences then you can leave out the argument &amp;lt;e&amp;gt;a_pref_manager&amp;lt;/e&amp;gt; of &amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt; and you can remove the whole &amp;lt;e&amp;gt;initialize_options&amp;lt;/e&amp;gt; feature.&lt;br /&gt;
&lt;br /&gt;
=== AST Processing ===&lt;br /&gt;
&lt;br /&gt;
The main part of your rule implementation consists of checking the source code for rule violations. Say, for example, that you want to check &amp;lt;e&amp;gt;if&amp;lt;/e&amp;gt; instructions to have certain properties. Then you would add a feature like &amp;lt;e&amp;gt;process_if (a_if_ast: IF_AS)&amp;lt;/e&amp;gt; to the section ''Rule checking''. Also, you would need to modify the &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt; feature by adding the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;a_checker.add_if_pre_action (agent process_if)&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Of course you may register as many such agents as you want.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
The ''title'' and the ''description'' of the rule may be constant strings, they may also be localized strings. The ''rule ID'' must be unique among all rules. It should not contain spaces and should be reasonably short. The main rules that come with ''Code Analysis'' have IDs that are numbered from CA001 to CA999 (many of which are not used).&lt;br /&gt;
&lt;br /&gt;
=== Formatted Violation Description ===&lt;br /&gt;
&lt;br /&gt;
Your rule should be able to produce a formatted description of a concrete rule violation. This description is for example used in the Code Analysis tool panel of the GUI. There, class names and feature names are enabled for pick-and-drop. Variable names, numbers, and strings will be displayed in a nice way, too. In addition, this description is used in command line mode. In order to produce normal, unformatted text, use &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add&amp;lt;/e&amp;gt;. For adding formatted elements use features like &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_local&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_feature_name&amp;lt;/e&amp;gt; and similar.&lt;br /&gt;
&lt;br /&gt;
You should store all the data you need for this description (variables names, numbers, etc.) in &amp;lt;e&amp;gt;{CA_RULE_VIOLATION}.long_description_info&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;format_violation_description&amp;lt;/e&amp;gt; can then retrieve this data for the formatted output. Here is a simple example of producing a formatted description:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
a_formatter.add (&amp;quot;Feature &amp;quot;)&lt;br /&gt;
if attached {STRING_32} a_violation.long_description_info.first as l_feat_name then&lt;br /&gt;
  a_formatter.add_feature_name (l_feat_name, a_violation.affected_class)&lt;br /&gt;
end&lt;br /&gt;
a_formatter.add (&amp;quot; is very long.&amp;quot;)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== More Customized Rules ==&lt;br /&gt;
&lt;br /&gt;
For rules that do not fit into a simple AST visitor scheme you best inherit your rule from &amp;lt;e&amp;gt;{CA_STANDARD_RULE}&amp;lt;/e&amp;gt;, too. You can for example register agents that get called when a ''class'' or a ''feature'' is processed. Based on these agents you can perform your customized analysis on the classes and/or features. Using ''multiple inheritance'' or just aggregation it should hardly be a problem to include any functionality you need for your analysis.&lt;br /&gt;
&lt;br /&gt;
== Accessing Type Information ==&lt;br /&gt;
&lt;br /&gt;
The AST classes do not contain ''type information''. Suppose your rule processes function calls. Feature calls in the AST do not contain any information on the types, such as the type of the result.&lt;br /&gt;
&lt;br /&gt;
The code analysis framework however provides functionality to retrieve the type of AST nodes. Before the analyzer lets a class be analyzed by all the rules it computes the types of the AST nodes of a class. Hence this data will be available to your rule afterwards.&lt;br /&gt;
&lt;br /&gt;
While your rule is being checked you can retrieve the type of node &amp;lt;e&amp;gt;a_node&amp;lt;/e&amp;gt; from feature &amp;lt;e&amp;gt;a_feature&amp;lt;/e&amp;gt; by calling &amp;lt;e&amp;gt;current_context.node_type (a_node: AST_EIFFEL; a_feature: FEATURE_I)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;{CA_RULE}.current_context&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; and contains other information about current rule checking, too, such as the currently processed class or the matchlist for this class.&lt;br /&gt;
&lt;br /&gt;
== Accessing the Control Flow Graph ==&lt;br /&gt;
&lt;br /&gt;
Some kinds of static code analysis need and use the ''control flow graph'' of a program. The code analysis framework supports rules that use the control flow graph. If there is at least one such rule, the code analyzer computes the control flow graph of the procedures of the analyzed class before letting the ''rule'' check this class.&lt;br /&gt;
&lt;br /&gt;
=== Worklist Algorithms ===&lt;br /&gt;
&lt;br /&gt;
''Control flow graph rules'' iterate over the control flow graph. They do it using a ''worklist''—a list of CFG edges that still have to be processed. At the beginning, the worklist contains all edges of the control flow graph. The algorithm will pick edges from the worklist for processing in an arbitrary order. The iteration stops as soon as there are no more edges left in the worklist. How will the worklist get smaller? Each edge that is processed is removed from the worklist. After processing you will have to decide dynamically whether to add all the outgoing (or incoming, depending on the direction) edges to the worklist. Like this you can take the fact into account that some analyses need certain edges to be processed more than once (a fixed point iteration is such an example).&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
A control flow analysis may iterate in either direction. For a forward-directed analysis inherit your rule from &amp;lt;e&amp;gt;{CA_CFG_FORWARD_RULE}&amp;lt;/e&amp;gt;, for a backward analysis use &amp;lt;e&amp;gt;{CA_CFG_BACKWARD_RULE}&amp;lt;/e&amp;gt; instead. In either case you will then have to implement the following deferred features:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;initialize_processing (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; : This is called before a routine is processed using the worklist. Essentially you may use it to initialize and prepare all the data structures you will need during analysis.&lt;br /&gt;
; &amp;lt;e&amp;gt;visit_edge (a_from, a_to: attached CA_CFG_BASIC_BLOCK): BOOLEAN&amp;lt;/e&amp;gt; : This will be called when an edge is being visited. Here, you can put the analysis. If you let &amp;lt;e&amp;gt;Result = False&amp;lt;/e&amp;gt; then no further edges will be added to the worklist. If in contrary you let &amp;lt;e&amp;gt;Result = True&amp;lt;/e&amp;gt; then edges will be added to the worklist: In a ''forward'' analysis all the ''outgoing'' edges of the current one will be added; in a ''backward'' analysis all the ''incoming'' edges will be added.&lt;br /&gt;
&lt;br /&gt;
=== Non-Worklist algorithms ===&lt;br /&gt;
&lt;br /&gt;
If your control flow graph does not fit into the structure of an algorithm as described above you may directly inherit from &amp;lt;e&amp;gt;{CA_CFG_RULE}&amp;lt;/e&amp;gt; and implement the feature &amp;lt;e&amp;gt;process_cfg (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; (in addition to the features explained above). In this case you do not have to use a worklist; basically you can process the control flow graph in any way you want.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15111</id>
		<title>CA Adding New Rules</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15111"/>
				<updated>2014-03-13T11:45:00Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* Worklist algorithms */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Command Line Usage|&amp;amp;lt;&amp;amp;lt; 5. Command Line Usage]] | [[User:Stefan/Code Analysis/Library Implementation|7. Library Implementation &amp;amp;gt;&amp;amp;gt;]] &amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
The Code Analysis framework was designed with regard to the fact that '''adding new rules''' should be as simple and as fast as possible. Looking at the initial set of rules that were implemented, nearly all of them have an implementation of less than 200 lines of code. Many of them use even less than 100 lines of code. Rules that search the code for certain patterns (this applies to the vast majority of rules) are particularly simple to implement.&lt;br /&gt;
&lt;br /&gt;
This page shows you how to implement a rule in the form of a class. After you have written such a class you must add the rule to the list of rules. This list is populated in &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.make&amp;lt;/e&amp;gt;. There, just below the lines where all the other rules are added add a line like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;rules.extend (create {YOUR_RULE}.make)&amp;lt;/e&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;e&amp;gt;YOUR_RULE&amp;lt;/e&amp;gt; must be replaced by the name of your rule class and the creation procedure (&amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt;) must be adapted if necessary.&lt;br /&gt;
&lt;br /&gt;
== Standard Rules ==&lt;br /&gt;
&lt;br /&gt;
All rules must conform to &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. The class you implement for a rule is on one hand responsible for checking the rule and contains metadata about the rule (i. e. title, description) on the other hand. As of now, rules must moreover conform to either &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;CA_CFG_RULE&amp;lt;/e&amp;gt;, both of which are subtypes of &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. A large number of possible rules are ''standard rules'', no matter whether they are trivial or more complicated.&lt;br /&gt;
&lt;br /&gt;
All ''Standard rules'' are checked by iterating over the [http://en.wikipedia.org/wiki/Abstract_syntax_tree abstract syntax tree] (AST) of the class code. The developer who adds a new rule can very well ignore the details thereof. He needs to know however which AST nodes his rule needs to process. For each type of AST node you need to add an agent so your routine will be called during the iteration on the AST.&lt;br /&gt;
&lt;br /&gt;
To start implementing your rule you have basically two possibilities. (1) You start from scratch, implementing all deferred features of &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or (2) you use the following template.&lt;br /&gt;
&lt;br /&gt;
=== Standard Rule Template ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
class&lt;br /&gt;
  CA_YOUR_RULE&lt;br /&gt;
&lt;br /&gt;
inherit&lt;br /&gt;
  CA_STANDARD_RULE&lt;br /&gt;
&lt;br /&gt;
create&lt;br /&gt;
  make&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Initialization&lt;br /&gt;
&lt;br /&gt;
  make (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initialization for `Current'.&lt;br /&gt;
    do&lt;br /&gt;
      make_with_defaults&lt;br /&gt;
        -- This initializes the attributes to their default values:&lt;br /&gt;
        -- Severity = warning&lt;br /&gt;
        -- Default Severity Score = 50 (`severity score' can be changed by user)&lt;br /&gt;
        -- Rule enabled by default = True (`Rule enabled' can be changed by user)&lt;br /&gt;
        -- Only for system wide checks = False&lt;br /&gt;
        -- Checks library classes = True&lt;br /&gt;
        -- Checks nonlibrary classes = True&lt;br /&gt;
&lt;br /&gt;
        initialize_options (a_pref_manager)&lt;br /&gt;
&lt;br /&gt;
        -- TODO: Add your initialization here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  initialize_options (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initializes the rule preferences.&lt;br /&gt;
    local&lt;br /&gt;
      l_factory: BASIC_PREFERENCE_FACTORY&lt;br /&gt;
    do&lt;br /&gt;
      create l_factory&lt;br /&gt;
     &lt;br /&gt;
        -- TODO: Add the initialization of your custom preferences here.&lt;br /&gt;
        -- Example:&lt;br /&gt;
--    threshold := l_factory.new_integer_preference_value (a_pref_manager,&lt;br /&gt;
--      preference_namespace + &amp;quot;Threshold&amp;quot;,&lt;br /&gt;
--      30)  -- default value&lt;br /&gt;
--    min_local_name_length.set_default_value (&amp;quot;30&amp;quot;) -- default value, too&lt;br /&gt;
--    min_local_name_length.set_validation_agent (agent is_integer_string_within_bounds (?, 1, 1_000_000))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add agents for the features in section `Rule checking' here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Rule checking&lt;br /&gt;
&lt;br /&gt;
  -- TODO: Add the AST processing here.&lt;br /&gt;
&lt;br /&gt;
feature -- Properties&lt;br /&gt;
&lt;br /&gt;
  title: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the title of your rule here.&lt;br /&gt;
      Result := &amp;quot;(Your title)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- TODO: Add the ID of your rule here. Should be unique!&lt;br /&gt;
  id: STRING_32 = &amp;quot;(YourID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  description: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the rule description here.&lt;br /&gt;
      Result :=  &amp;quot;(Your description)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add a formatted description of a concrete violation of this rule here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let us have a closer look at the various parts of a rule class.&lt;br /&gt;
&lt;br /&gt;
=== Initialization ===&lt;br /&gt;
&lt;br /&gt;
Calling &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt; initializes the attributes to their default values and makes sure that the class invariant is true. If you want to set an attribute to a custom value you can do so by setting it after the call to &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The creation procedure from the template takes an argument of type &amp;lt;e&amp;gt;PREFERENCE_MANAGER&amp;lt;/e&amp;gt;. This is used for initializing preferences that are specific to your rule. Such preferences usually represent integral or boolean values. If you do ''not'' need any custom preferences then you can leave out the argument &amp;lt;e&amp;gt;a_pref_manager&amp;lt;/e&amp;gt; of &amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt; and you can remove the whole &amp;lt;e&amp;gt;initialize_options&amp;lt;/e&amp;gt; feature.&lt;br /&gt;
&lt;br /&gt;
=== AST Processing ===&lt;br /&gt;
&lt;br /&gt;
The main part of your rule implementation consists of checking the source code for rule violations. Say, for example, that you want to check &amp;lt;e&amp;gt;if&amp;lt;/e&amp;gt; instructions to have certain properties. Then you would add a feature like &amp;lt;e&amp;gt;process_if (a_if_ast: IF_AS)&amp;lt;/e&amp;gt; to the section ''Rule checking''. Also, you would need to modify the &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt; feature by adding the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;a_checker.add_if_pre_action (agent process_if)&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Of course you may register as many such agents as you want.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
The ''title'' and the ''description'' of the rule may be constant strings, they may also be localized strings. The ''rule ID'' must be unique among all rules. It should not contain spaces and should be reasonably short. The main rules that come with ''Code Analysis'' have IDs that are numbered from CA001 to CA999 (many of which are not used).&lt;br /&gt;
&lt;br /&gt;
=== Formatted Violation Description ===&lt;br /&gt;
&lt;br /&gt;
Your rule should be able to produce a formatted description of a concrete rule violation. This description is for example used in the Code Analysis tool panel of the GUI. There, class names and feature names are enabled for pick-and-drop. Variable names, numbers, and strings will be displayed in a nice way, too. In addition, this description is used in command line mode. In order to produce normal, unformatted text, use &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add&amp;lt;/e&amp;gt;. For adding formatted elements use features like &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_local&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_feature_name&amp;lt;/e&amp;gt; and similar.&lt;br /&gt;
&lt;br /&gt;
You should store all the data you need for this description (variables names, numbers, etc.) in &amp;lt;e&amp;gt;{CA_RULE_VIOLATION}.long_description_info&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;format_violation_description&amp;lt;/e&amp;gt; can then retrieve this data for the formatted output. Here is a simple example of producing a formatted description:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
a_formatter.add (&amp;quot;Feature &amp;quot;)&lt;br /&gt;
if attached {STRING_32} a_violation.long_description_info.first as l_feat_name then&lt;br /&gt;
  a_formatter.add_feature_name (l_feat_name, a_violation.affected_class)&lt;br /&gt;
end&lt;br /&gt;
a_formatter.add (&amp;quot; is very long.&amp;quot;)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== More Customized Rules ==&lt;br /&gt;
&lt;br /&gt;
For rules that do not fit into a simple AST visitor scheme you best inherit your rule from &amp;lt;e&amp;gt;{CA_STANDARD_RULE}&amp;lt;/e&amp;gt;, too. You can for example register agents that get called when a ''class'' or a ''feature'' is processed. Based on these agents you can perform your customized analysis on the classes and/or features. Using ''multiple inheritance'' or just aggregation it should hardly be a problem to include any functionality you need for your analysis.&lt;br /&gt;
&lt;br /&gt;
== Accessing Type Information ==&lt;br /&gt;
&lt;br /&gt;
The AST classes do not contain ''type information''. Suppose your rule processes function calls. Feature calls in the AST do not contain any information on the types, such as the type of the result.&lt;br /&gt;
&lt;br /&gt;
The code analysis framework however provides functionality to retrieve the type of AST nodes. Before the analyzer lets a class be analyzed by all the rules it computes the types of the AST nodes of a class. Hence this data will be available to your rule afterwards.&lt;br /&gt;
&lt;br /&gt;
While your rule is being checked you can retrieve the type of node &amp;lt;e&amp;gt;a_node&amp;lt;/e&amp;gt; from feature &amp;lt;e&amp;gt;a_feature&amp;lt;/e&amp;gt; by calling &amp;lt;e&amp;gt;current_context.node_type (a_node: AST_EIFFEL; a_feature: FEATURE_I)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;{CA_RULE}.current_context&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; and contains other information about current rule checking, too, such as the currently processed class or the matchlist for this class.&lt;br /&gt;
&lt;br /&gt;
== Accessing the Control Flow Graph ==&lt;br /&gt;
&lt;br /&gt;
Some kinds of static code analysis need and use the ''control flow graph'' of a program. The code analysis framework supports rules that use the control flow graph. If there is at least one such rule, the code analyzer computes the control flow graph of the procedures of the analyzed class before letting the ''rule'' check this class.&lt;br /&gt;
&lt;br /&gt;
=== Worklist Algorithms ===&lt;br /&gt;
&lt;br /&gt;
''Control flow graph rules'' iterate over the control flow graph. They do it using a ''worklist''—a list of CFG edges that still have to be processed. At the beginning, the worklist contains all edges of the control flow graph. The algorithm will pick edges from the worklist for processing in an arbitrary order. The iteration stops as soon as there are no more edges left in the worklist. How will the worklist get smaller? Each edge that is processed is removed from the worklist. After processing you will have to decide dynamically whether to add all the outgoing (or incoming, depending on the direction) edges to the worklist. Like this you can take the fact into account that some analyses need certain edges to be processed more than once (a fixed point iteration is such an example).&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
A control flow analysis may iterate in either direction. For a forward-directed analysis inherit your rule from &amp;lt;e&amp;gt;{CA_CFG_FORWARD_RULE}&amp;lt;/e&amp;gt;, for a backward analysis use &amp;lt;e&amp;gt;{CA_CFG_BACKWARD_RULE}&amp;lt;/e&amp;gt; instead. In either case you will then have to implement the following deferred features:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;initialize_processing (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; : This is called before a routine is processed using the worklist. Essentially you may use it to initialize and prepare all the data structures you will need during analysis.&lt;br /&gt;
; &amp;lt;e&amp;gt;visit_edge (a_from, a_to: attached CA_CFG_BASIC_BLOCK): BOOLEAN&amp;lt;/e&amp;gt; : This will be called when an edge is being visited. Here, you can put the analysis. If you let &amp;lt;e&amp;gt;Result = False&amp;lt;/e&amp;gt; then no further edges will be added to the worklist. If in contrary you let &amp;lt;e&amp;gt;Result = True&amp;lt;/e&amp;gt; then edges will be added to the worklist: In a ''forward'' analysis all the ''outgoing'' edges of the current one will be added; in a ''backward'' analysis all the ''incoming'' edges will be added.&lt;br /&gt;
&lt;br /&gt;
=== Non-worklist algorithms ===&lt;br /&gt;
&lt;br /&gt;
If your control flow graph does not fit into the structure of an algorithm as described above you may directly inherit from &amp;lt;e&amp;gt;{CA_CFG_RULE}&amp;lt;/e&amp;gt; and implement the feature &amp;lt;e&amp;gt;process_cfg (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; (in addition to the features explained above). In this case you do not have to use a worklist; basically you can process the control flow graph in any way you want.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15110</id>
		<title>CA Adding New Rules</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15110"/>
				<updated>2014-03-13T11:35:15Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* AST processing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Command Line Usage|&amp;amp;lt;&amp;amp;lt; 5. Command Line Usage]] | [[User:Stefan/Code Analysis/Library Implementation|7. Library Implementation &amp;amp;gt;&amp;amp;gt;]] &amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
The Code Analysis framework was designed with regard to the fact that '''adding new rules''' should be as simple and as fast as possible. Looking at the initial set of rules that were implemented, nearly all of them have an implementation of less than 200 lines of code. Many of them use even less than 100 lines of code. Rules that search the code for certain patterns (this applies to the vast majority of rules) are particularly simple to implement.&lt;br /&gt;
&lt;br /&gt;
This page shows you how to implement a rule in the form of a class. After you have written such a class you must add the rule to the list of rules. This list is populated in &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.make&amp;lt;/e&amp;gt;. There, just below the lines where all the other rules are added add a line like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;rules.extend (create {YOUR_RULE}.make)&amp;lt;/e&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;e&amp;gt;YOUR_RULE&amp;lt;/e&amp;gt; must be replaced by the name of your rule class and the creation procedure (&amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt;) must be adapted if necessary.&lt;br /&gt;
&lt;br /&gt;
== Standard Rules ==&lt;br /&gt;
&lt;br /&gt;
All rules must conform to &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. The class you implement for a rule is on one hand responsible for checking the rule and contains metadata about the rule (i. e. title, description) on the other hand. As of now, rules must moreover conform to either &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;CA_CFG_RULE&amp;lt;/e&amp;gt;, both of which are subtypes of &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. A large number of possible rules are ''standard rules'', no matter whether they are trivial or more complicated.&lt;br /&gt;
&lt;br /&gt;
All ''Standard rules'' are checked by iterating over the [http://en.wikipedia.org/wiki/Abstract_syntax_tree abstract syntax tree] (AST) of the class code. The developer who adds a new rule can very well ignore the details thereof. He needs to know however which AST nodes his rule needs to process. For each type of AST node you need to add an agent so your routine will be called during the iteration on the AST.&lt;br /&gt;
&lt;br /&gt;
To start implementing your rule you have basically two possibilities. (1) You start from scratch, implementing all deferred features of &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or (2) you use the following template.&lt;br /&gt;
&lt;br /&gt;
=== Standard Rule Template ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
class&lt;br /&gt;
  CA_YOUR_RULE&lt;br /&gt;
&lt;br /&gt;
inherit&lt;br /&gt;
  CA_STANDARD_RULE&lt;br /&gt;
&lt;br /&gt;
create&lt;br /&gt;
  make&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Initialization&lt;br /&gt;
&lt;br /&gt;
  make (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initialization for `Current'.&lt;br /&gt;
    do&lt;br /&gt;
      make_with_defaults&lt;br /&gt;
        -- This initializes the attributes to their default values:&lt;br /&gt;
        -- Severity = warning&lt;br /&gt;
        -- Default Severity Score = 50 (`severity score' can be changed by user)&lt;br /&gt;
        -- Rule enabled by default = True (`Rule enabled' can be changed by user)&lt;br /&gt;
        -- Only for system wide checks = False&lt;br /&gt;
        -- Checks library classes = True&lt;br /&gt;
        -- Checks nonlibrary classes = True&lt;br /&gt;
&lt;br /&gt;
        initialize_options (a_pref_manager)&lt;br /&gt;
&lt;br /&gt;
        -- TODO: Add your initialization here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  initialize_options (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initializes the rule preferences.&lt;br /&gt;
    local&lt;br /&gt;
      l_factory: BASIC_PREFERENCE_FACTORY&lt;br /&gt;
    do&lt;br /&gt;
      create l_factory&lt;br /&gt;
     &lt;br /&gt;
        -- TODO: Add the initialization of your custom preferences here.&lt;br /&gt;
        -- Example:&lt;br /&gt;
--    threshold := l_factory.new_integer_preference_value (a_pref_manager,&lt;br /&gt;
--      preference_namespace + &amp;quot;Threshold&amp;quot;,&lt;br /&gt;
--      30)  -- default value&lt;br /&gt;
--    min_local_name_length.set_default_value (&amp;quot;30&amp;quot;) -- default value, too&lt;br /&gt;
--    min_local_name_length.set_validation_agent (agent is_integer_string_within_bounds (?, 1, 1_000_000))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add agents for the features in section `Rule checking' here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Rule checking&lt;br /&gt;
&lt;br /&gt;
  -- TODO: Add the AST processing here.&lt;br /&gt;
&lt;br /&gt;
feature -- Properties&lt;br /&gt;
&lt;br /&gt;
  title: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the title of your rule here.&lt;br /&gt;
      Result := &amp;quot;(Your title)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- TODO: Add the ID of your rule here. Should be unique!&lt;br /&gt;
  id: STRING_32 = &amp;quot;(YourID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  description: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the rule description here.&lt;br /&gt;
      Result :=  &amp;quot;(Your description)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add a formatted description of a concrete violation of this rule here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let us have a closer look at the various parts of a rule class.&lt;br /&gt;
&lt;br /&gt;
=== Initialization ===&lt;br /&gt;
&lt;br /&gt;
Calling &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt; initializes the attributes to their default values and makes sure that the class invariant is true. If you want to set an attribute to a custom value you can do so by setting it after the call to &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The creation procedure from the template takes an argument of type &amp;lt;e&amp;gt;PREFERENCE_MANAGER&amp;lt;/e&amp;gt;. This is used for initializing preferences that are specific to your rule. Such preferences usually represent integral or boolean values. If you do ''not'' need any custom preferences then you can leave out the argument &amp;lt;e&amp;gt;a_pref_manager&amp;lt;/e&amp;gt; of &amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt; and you can remove the whole &amp;lt;e&amp;gt;initialize_options&amp;lt;/e&amp;gt; feature.&lt;br /&gt;
&lt;br /&gt;
=== AST Processing ===&lt;br /&gt;
&lt;br /&gt;
The main part of your rule implementation consists of checking the source code for rule violations. Say, for example, that you want to check &amp;lt;e&amp;gt;if&amp;lt;/e&amp;gt; instructions to have certain properties. Then you would add a feature like &amp;lt;e&amp;gt;process_if (a_if_ast: IF_AS)&amp;lt;/e&amp;gt; to the section ''Rule checking''. Also, you would need to modify the &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt; feature by adding the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;a_checker.add_if_pre_action (agent process_if)&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Of course you may register as many such agents as you want.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
The ''title'' and the ''description'' of the rule may be constant strings, they may also be localized strings. The ''rule ID'' must be unique among all rules. It should not contain spaces and should be reasonably short. The main rules that come with ''Code Analysis'' have IDs that are numbered from CA001 to CA999 (many of which are not used).&lt;br /&gt;
&lt;br /&gt;
=== Formatted Violation Description ===&lt;br /&gt;
&lt;br /&gt;
Your rule should be able to produce a formatted description of a concrete rule violation. This description is for example used in the Code Analysis tool panel of the GUI. There, class names and feature names are enabled for pick-and-drop. Variable names, numbers, and strings will be displayed in a nice way, too. In addition, this description is used in command line mode. In order to produce normal, unformatted text, use &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add&amp;lt;/e&amp;gt;. For adding formatted elements use features like &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_local&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_feature_name&amp;lt;/e&amp;gt; and similar.&lt;br /&gt;
&lt;br /&gt;
You should store all the data you need for this description (variables names, numbers, etc.) in &amp;lt;e&amp;gt;{CA_RULE_VIOLATION}.long_description_info&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;format_violation_description&amp;lt;/e&amp;gt; can then retrieve this data for the formatted output. Here is a simple example of producing a formatted description:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
a_formatter.add (&amp;quot;Feature &amp;quot;)&lt;br /&gt;
if attached {STRING_32} a_violation.long_description_info.first as l_feat_name then&lt;br /&gt;
  a_formatter.add_feature_name (l_feat_name, a_violation.affected_class)&lt;br /&gt;
end&lt;br /&gt;
a_formatter.add (&amp;quot; is very long.&amp;quot;)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== More Customized Rules ==&lt;br /&gt;
&lt;br /&gt;
For rules that do not fit into a simple AST visitor scheme you best inherit your rule from &amp;lt;e&amp;gt;{CA_STANDARD_RULE}&amp;lt;/e&amp;gt;, too. You can for example register agents that get called when a ''class'' or a ''feature'' is processed. Based on these agents you can perform your customized analysis on the classes and/or features. Using ''multiple inheritance'' or just aggregation it should hardly be a problem to include any functionality you need for your analysis.&lt;br /&gt;
&lt;br /&gt;
== Accessing Type Information ==&lt;br /&gt;
&lt;br /&gt;
The AST classes do not contain ''type information''. Suppose your rule processes function calls. Feature calls in the AST do not contain any information on the types, such as the type of the result.&lt;br /&gt;
&lt;br /&gt;
The code analysis framework however provides functionality to retrieve the type of AST nodes. Before the analyzer lets a class be analyzed by all the rules it computes the types of the AST nodes of a class. Hence this data will be available to your rule afterwards.&lt;br /&gt;
&lt;br /&gt;
While your rule is being checked you can retrieve the type of node &amp;lt;e&amp;gt;a_node&amp;lt;/e&amp;gt; from feature &amp;lt;e&amp;gt;a_feature&amp;lt;/e&amp;gt; by calling &amp;lt;e&amp;gt;current_context.node_type (a_node: AST_EIFFEL; a_feature: FEATURE_I)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;{CA_RULE}.current_context&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; and contains other information about current rule checking, too, such as the currently processed class or the matchlist for this class.&lt;br /&gt;
&lt;br /&gt;
== Accessing the Control Flow Graph ==&lt;br /&gt;
&lt;br /&gt;
Some kinds of static code analysis need and use the ''control flow graph'' of a program. The code analysis framework supports rules that use the control flow graph. If there is at least one such rule, the code analyzer computes the control flow graph of the procedures of the analyzed class before letting the ''rule'' check this class.&lt;br /&gt;
&lt;br /&gt;
=== Worklist algorithms ===&lt;br /&gt;
&lt;br /&gt;
''Control flow graph rules'' iterate over the control flow graph. They do it using a ''worklist''—a list of CFG edges that still have to be processed. At the beginning, the worklist contains all edges of the control flow graph. The algorithm will pick edges from the worklist for processing in an arbitrary order. The iteration stops as soon as there are no more edges left in the worklist. How will the worklist get smaller? Each edge that is processed is removed from the worklist. After processing you will have to decide dynamically whether to add all the outgoing (or incoming, depending on the direction) edges to the worklist. Like this you can take the fact into account that some analyses need certain edges to be processed more than once (a fixed point iteration is such an example).&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
A control flow analysis may iterate in either direction. For a forward-directed analysis inherit your rule from &amp;lt;e&amp;gt;{CA_CFG_FORWARD_RULE}&amp;lt;/e&amp;gt;, for a backward analysis use &amp;lt;e&amp;gt;{CA_CFG_BACKWARD_RULE}&amp;lt;/e&amp;gt; instead. In either case you will then have to implement the following deferred features:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;initialize_processing (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; : This is called before a routine is processed using the worklist. Essentially you may use it to initialize and prepare all the data structures you will need during analysis.&lt;br /&gt;
; &amp;lt;e&amp;gt;visit_edge (a_from, a_to: attached CA_CFG_BASIC_BLOCK): BOOLEAN&amp;lt;/e&amp;gt; : This will be called when an edge is being visited. Here, you can put the analysis. If you let &amp;lt;e&amp;gt;Result = False&amp;lt;/e&amp;gt; then no further edges will be added to the worklist. If in contrary you let &amp;lt;e&amp;gt;Result = True&amp;lt;/e&amp;gt; then edges will be added to the worklist: In a ''forward'' analysis all the ''outgoing'' edges of the current one will be added; in a ''backward'' analysis all the ''incoming'' edges will be added.&lt;br /&gt;
&lt;br /&gt;
=== Non-worklist algorithms ===&lt;br /&gt;
&lt;br /&gt;
If your control flow graph does not fit into the structure of an algorithm as described above you may directly inherit from &amp;lt;e&amp;gt;{CA_CFG_RULE}&amp;lt;/e&amp;gt; and implement the feature &amp;lt;e&amp;gt;process_cfg (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; (in addition to the features explained above). In this case you do not have to use a worklist; basically you can process the control flow graph in any way you want.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15109</id>
		<title>CA UI Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15109"/>
				<updated>2014-03-13T09:39:29Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* Command-line Interface */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Library Implementation|&amp;amp;lt;&amp;amp;lt; 7. Library Implementation]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
The classes of the graphical user interface of the code analyzer are all located in the ''interface'' cluster of ''EVE'', in the subfolder ''graphical &amp;gt; tools &amp;gt; code_analysis''. Here is a short overview of what the single classes do:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL}&amp;lt;/e&amp;gt; : Represents the code analysis GUI tool. Contains the tool title and icon, otherwise not much interesting stuff.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL_PANEL}&amp;lt;/e&amp;gt; : The graphical panel for the code analysis tool. It contains buttons, labels, the rule violations table view, and other user interface elements.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; : 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_BENCH_HELPER}&amp;lt;/e&amp;gt; : A helper class for the integration of the code analysis tool. It contains shared instances of &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;, which are used by the GUI.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_SHOW_PREFERENCES_COMMAND}&amp;lt;/e&amp;gt; : The command is used by the ''Preferences'' button in the panel.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_FIX_EXECUTOR}&amp;lt;/e&amp;gt; : This class [[User:Stefan/Code Analysis/Using Analysis Results#Fixing Rule Violations|fixes]] a rule violation that has been found by the code analysis tool.&lt;br /&gt;
&lt;br /&gt;
These are roughly the class relations for the code analysis GUI:&lt;br /&gt;
[[File:CA GUI Diagram.png|thumb|center|650px|The most interesting class relations of the code analysis GUI.]]&lt;br /&gt;
&lt;br /&gt;
=== Caching ===&lt;br /&gt;
&lt;br /&gt;
It is a common case that GUI users run the code analyzer again after having made some changes to the code. We do not need to analyze the same unchanged code again and again. Therefore code analysis caches the results in memory. This only applies to the GUI mode.&lt;br /&gt;
&lt;br /&gt;
Code analysis uses cached results exactly in one case: when the whole system is analyzed and the previous analysis was on the whole system, too.&lt;br /&gt;
&lt;br /&gt;
The caching functionality is implemented in &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;. When the command for analyzing the system is executed, the timestamps of the last modification of the classes are stored in &amp;lt;e&amp;gt;analysis_timestamp : HASH_TABLE [INTEGER, CLASS_I]&amp;lt;/e&amp;gt; before the analysis. Note that the cached results (the rule violations) themselves are managed by &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt;. The only difference to a non-cached analysis is that the rule violations are not deleted by &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; before the next analysis. Then, in case the next command is also for analyzing the whole system, the current timestamps are compared to the stored timestamps. Any class that has been changed in the meantime will be analyzed again; for any unchanged class the rule violations are taken from the cache.&lt;br /&gt;
&lt;br /&gt;
=== Example Command: Analyze One Class ===&lt;br /&gt;
&lt;br /&gt;
We will now roughly go through the code that is executed on the GUI part when the user wants to analyze a single class. As mentioned in Chapter [[User:Stefan/Code Analysis/Running the Analyzer|Running the Analyzer]], this can be done using the class context menu or by dropping the class stone on the button ''Analyze Item''.&lt;br /&gt;
&lt;br /&gt;
In any case &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}.execute_with_stone&amp;lt;/e&amp;gt; is called, which delegates to &amp;lt;e&amp;gt;execute_with_stone_content&amp;lt;/e&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
execute_with_stone (a_stone: STONE)&lt;br /&gt;
    -- Execute with `a_stone'.&lt;br /&gt;
  do&lt;br /&gt;
    execute_with_stone_content (a_stone, Void)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
execute_with_stone_content (a_stone: STONE; a_content: SD_CONTENT)&lt;br /&gt;
    -- Execute with `a_stone'.&lt;br /&gt;
  local&lt;br /&gt;
    l_save_confirm: ES_DISCARDABLE_COMPILE_SAVE_FILES_PROMPT&lt;br /&gt;
    l_classes: DS_ARRAYED_LIST [CLASS_I]&lt;br /&gt;
  do&lt;br /&gt;
      -- Show the tool right from the start.&lt;br /&gt;
    show_ca_tool&lt;br /&gt;
&lt;br /&gt;
    if not eiffel_project.is_compiling then&lt;br /&gt;
      if window_manager.has_modified_windows then&lt;br /&gt;
        create l_classes.make_default&lt;br /&gt;
        window_manager.all_modified_classes.do_all (agent l_classes.force_last)&lt;br /&gt;
        create l_save_confirm.make (l_classes)&lt;br /&gt;
        l_save_confirm.set_button_action (l_save_confirm.dialog_buttons.yes_button, agent save_compile_and_analyze (a_stone))&lt;br /&gt;
        l_save_confirm.set_button_action (l_save_confirm.dialog_buttons.no_button, agent compile_and_analyze (a_stone))&lt;br /&gt;
        l_save_confirm.show_on_active_window&lt;br /&gt;
      else&lt;br /&gt;
        compile_and_analyze (a_stone)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there are modified, unsaved windows a save confirmation dialog is displayed. Eventually program flow passes on to &amp;lt;e&amp;gt;compile_and_analyze&amp;lt;/e&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
compile_and_analyze (a_stone: STONE)&lt;br /&gt;
    -- Compile project and perform analysis of stone `a_stone'.&lt;br /&gt;
  local&lt;br /&gt;
    l_helper: ES_CODE_ANALYSIS_BENCH_HELPER&lt;br /&gt;
    l_dialog: ES_INFORMATION_PROMPT&lt;br /&gt;
  do&lt;br /&gt;
      -- Compile the project and only analyze if the compilation was successful.&lt;br /&gt;
    eiffel_project.quick_melt (True, True, True)&lt;br /&gt;
    if eiffel_project.successful then&lt;br /&gt;
      create l_helper&lt;br /&gt;
      if l_helper.code_analyzer.is_running then&lt;br /&gt;
        create l_dialog.make_standard (ca_messages.already_running_long)&lt;br /&gt;
        l_dialog.show_on_active_window&lt;br /&gt;
      else&lt;br /&gt;
        perform_analysis (a_stone)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;eiffel_project.quick_melt&amp;lt;/e&amp;gt; starts the compilation. A successful compilation is required for code analysis; otherwise nothing is analyzed. After compilation has succeeded we check if code analysis is already running. If this is the case then a dialog is displayed. If on the other hand this last possible obstacle is not present we finally start analyzing by calling &amp;lt;e&amp;gt;perform_analysis&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
perform_analysis (a_stone: STONE)&lt;br /&gt;
    -- Analyze `a_stone' only.&lt;br /&gt;
  local&lt;br /&gt;
    l_helper: ES_CODE_ANALYSIS_BENCH_HELPER&lt;br /&gt;
    l_scope_label: EV_LABEL&lt;br /&gt;
  do&lt;br /&gt;
      -- For simplicity let us assume that `a_stone' does not&lt;br /&gt;
      -- correspond to the system or is equivalent to it.&lt;br /&gt;
    last_was_analyze_all := False&lt;br /&gt;
&lt;br /&gt;
    create l_helper&lt;br /&gt;
    code_analyzer := l_helper.code_analyzer&lt;br /&gt;
    code_analyzer.clear_classes_to_analyze&lt;br /&gt;
    code_analyzer.rule_violations.wipe_out&lt;br /&gt;
&lt;br /&gt;
    l_scope_label := ca_tool.panel.scope_label&lt;br /&gt;
&lt;br /&gt;
    if attached {CLASSC_STONE} a_stone as s then&lt;br /&gt;
      code_analyzer.add_class (s.class_i.config_class)&lt;br /&gt;
      l_scope_label.set_text (s.class_name)&lt;br /&gt;
      l_scope_label.set_foreground_color (create {EV_COLOR}.make_with_8_bit_rgb (140, 140, 255))&lt;br /&gt;
      l_scope_label.set_pebble (s)&lt;br /&gt;
      l_scope_label.set_pick_and_drop_mode&lt;br /&gt;
      l_scope_label.set_tooltip (ca_messages.class_scope_tooltip)&lt;br /&gt;
    elseif [...]&lt;br /&gt;
    [...]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    disable_tool_button&lt;br /&gt;
    window_manager.display_message (ca_messages.status_bar_running)&lt;br /&gt;
    code_analyzer.add_completed_action (agent analysis_completed)&lt;br /&gt;
    code_analyzer.analyze&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The code that deals with stones other than classes is omitted.)&lt;br /&gt;
&lt;br /&gt;
At the start of the routine the code analyzer instance is retrieved from the helper class. All classes that may have been addedbefore, are removed. All previous rule violations are removed as well. The if clause creates a stone for the ''Last Scope'' label in the graphical panel. Then, the button in the tool is disabled so that starting another analysis is prevented until the current one has completed. Finally, the analysis is started. As soon as the analysis has completed &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}.analysis_completed&amp;lt;/e&amp;gt; is called. In this procedure the rule violations (and possibly the exceptions) are retrieved from the code analyzer and displayed in the list in the tool panel.&lt;br /&gt;
&lt;br /&gt;
== Command-Line Interface ==&lt;br /&gt;
&lt;br /&gt;
The whole command-line functionality of the code analyzer is located in the class &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. It is located in the ''tty'' cluster of ''EVE''. &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt; is invoked by &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the root class for the ''batch'' (command-line) version of EiffelStudio. In &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the invocation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
elseif option.is_equal (&amp;quot;-code-analysis&amp;quot;) then&lt;br /&gt;
  l_at_args := arguments_in_range (current_option + 1, argument_count)&lt;br /&gt;
  current_option := argument_count + 1&lt;br /&gt;
  create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any command-line arguments after ''-code-analysis'' are passed on to &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. This class, in its creation procedure, processes the arguments as described in [[User:Stefan/Code_Analysis/Command Line Usage|Command Line Usage]]. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure &amp;lt;e&amp;gt;execute&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; of course uses the ''code_analysis'' library and the previously described interface of &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;. After analysis a list of rule violations is output to the command-line. In the code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
across l_code_analyzer.rule_violations as l_vlist loop&lt;br /&gt;
  if not l_vlist.item.is_empty then&lt;br /&gt;
    l_has_violations := True&lt;br /&gt;
      -- Always sort the rule violations by the class they are referring to.&lt;br /&gt;
    output_window.add (ca_messages.cmd_class + l_vlist.key.name + &amp;quot;':%N&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting.&lt;br /&gt;
    across l_vlist.item as ic loop&lt;br /&gt;
      l_rule_name := ic.item.rule.title&lt;br /&gt;
      l_rule_id := ic.item.rule.id&lt;br /&gt;
      if attached ic.item.location as l_loc then&lt;br /&gt;
        l_line := ic.item.location.line.out&lt;br /&gt;
        l_col := ic.item.location.column.out&lt;br /&gt;
        output_window.add (&amp;quot;  (&amp;quot; + l_line + &amp;quot;:&amp;quot; + l_col + &amp;quot;): &amp;quot;&lt;br /&gt;
          + l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      else -- No location attached. Print without location.&lt;br /&gt;
        output_window.add (&amp;quot;  &amp;quot;	+ l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      ic.item.format_violation_description (output_window)&lt;br /&gt;
      output_window.add (&amp;quot;%N&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not l_has_violations then output_window.add (ca_messages.no_issues + &amp;quot;%N&amp;quot;) end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15108</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15108"/>
				<updated>2014-03-12T15:50:55Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* Rule checking */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] | [[User:Stefan/Code Analysis/UI Implementation|8. UI Implementation &amp;amp;gt; &amp;amp;gt;]]&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# The framework—by far the largest part, with the rule checking, the rules, the control flow graph functionality, and more—is represented as a ''library'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
The whole '''code analysis framework''' is located in the '''library ''code_analysis'''''.&lt;br /&gt;
&lt;br /&gt;
== Class Relations ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows an overview of the relations between the classes of the code analysis framework. All classes are located in the ''code_analysis'' library except for &amp;lt;e&amp;gt;CLASS_C&amp;lt;/e&amp;gt; (EiffelStudio), &amp;lt;e&amp;gt;ROTA_TIMED_TASK_I&amp;lt;/e&amp;gt; (''ecosystem'' cluster), &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; (command-line interface), and &amp;lt;e&amp;gt;ES_CODE_ANALYSIS_BENCH_HELPER&amp;lt;/e&amp;gt; (GUI).&lt;br /&gt;
&lt;br /&gt;
[[File:CA Framework Diagram.png|thumb|center|800px|The most interesting classes of the code analysis framework.]]&lt;br /&gt;
&lt;br /&gt;
== Interface ==&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Rule Checking ==&lt;br /&gt;
&lt;br /&gt;
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'', &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;. In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt; this task (&amp;lt;e&amp;gt;l_task&amp;lt;/e&amp;gt;) is invoked as follows:&lt;br /&gt;
&lt;br /&gt;
=== In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed)&lt;br /&gt;
l_task.set_output_actions (output_actions)&lt;br /&gt;
rota.run_task (l_task)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; essentially runs the whole analysis. Like all other conformants to &amp;lt;e&amp;gt;{ROTA_TASK_I}&amp;lt;/e&amp;gt; this class executes a series of ''steps'' between which the user interface gets some time to process its events. In &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; each step analyses one class. This means that a class is checked by ''all'' the rules for violations. The following code does that:&lt;br /&gt;
&lt;br /&gt;
=== From &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
step&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
  do&lt;br /&gt;
    if has_next_step then&lt;br /&gt;
        -- Gather type information&lt;br /&gt;
      type_recorder.clear&lt;br /&gt;
      type_recorder.analyze_class (classes.item)&lt;br /&gt;
      context.set_node_types (type_recorder.node_types)&lt;br /&gt;
      context.set_checking_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      across rules as l_rules loop&lt;br /&gt;
          -- If rule is non-standard then it will not be checked by l_rules_checker.&lt;br /&gt;
          -- We will have the rule check the current class here:&lt;br /&gt;
        if&lt;br /&gt;
          l_rules.item.is_enabled.value&lt;br /&gt;
          and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule&lt;br /&gt;
        then&lt;br /&gt;
          l_cfg_rule.check_class (classes.item)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
        -- Status output.&lt;br /&gt;
      if output_actions /= Void then&lt;br /&gt;
        output_actions.call ([ca_messages.analyzing_class (classes.item.name)])&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      rules_checker.run_on_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      classes.forth&lt;br /&gt;
      has_next_step := not classes.after&lt;br /&gt;
      if not has_next_step then&lt;br /&gt;
        completed_action.call ([exceptions])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  rescue&lt;br /&gt;
      -- Instant error output.&lt;br /&gt;
    if output_actions /= Void then&lt;br /&gt;
      output_actions.call ([ca_messages.error_on_class (classes.item.name)])&lt;br /&gt;
    end&lt;br /&gt;
    exceptions.extend ([exception_manager.last_exception, classes.item])&lt;br /&gt;
      -- Jump to the next class.&lt;br /&gt;
    classes.forth&lt;br /&gt;
    has_next_step := not classes.after&lt;br /&gt;
    if not has_next_step then&lt;br /&gt;
      completed_action.call ([exceptions])&lt;br /&gt;
    end&lt;br /&gt;
    retry&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;type_recorder&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_AST_TYPE_RECORDER}&amp;lt;/e&amp;gt;. 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. &amp;lt;e&amp;gt;context&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;e&amp;gt;across&amp;lt;/e&amp;gt; loop only checks ''control flow graph rules''. All the ''standard'' rules are checked by the line &amp;lt;e&amp;gt;rules_checker.run_on_class (classes.item)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;rules_checker&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt;. This is the class where each rule must register the AST nodes the rule visits. &amp;lt;e&amp;gt;run_on_class&amp;lt;/e&amp;gt; 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. &amp;lt;e&amp;gt;step&amp;lt;/e&amp;gt; is executed repeatedly until there are no classes left to analyze.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;e&amp;gt;rescue&amp;lt;/e&amp;gt; clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.&lt;br /&gt;
&lt;br /&gt;
=== Checking ''Standard'' Rules ===&lt;br /&gt;
&lt;br /&gt;
The relatively large class &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; is responsible for checking ''standard rules''. It does this in a straightforward way. It is a subclass of &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt;, a realization of a visitor on the AST.&lt;br /&gt;
&lt;br /&gt;
Rules can register their actions with &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; by calling a procedure like &amp;lt;e&amp;gt;add_bin_lt_pre_action (a_action: attached PROCEDURE [ANY, TUPLE [BIN_LT_AS]])&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&amp;lt;/e&amp;gt;. These &amp;quot;pre&amp;quot; and &amp;quot;post&amp;quot; actions exist for many other types of AST nodes as well. All the registered actions are stored in &amp;lt;e&amp;gt;ACTION_SEQUENCE&amp;lt;/e&amp;gt; variables:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
if_pre_actions, if_post_actions: ACTION_SEQUENCE [TUPLE [IF_AS]]&lt;br /&gt;
&lt;br /&gt;
add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&lt;br /&gt;
  do&lt;br /&gt;
    if_post_actions.extend (a_action)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding visitor procedures are redefined. This is done is the following way:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_if_as (a_if: IF_AS)&lt;br /&gt;
  do&lt;br /&gt;
    if_pre_actions.call ([a_if])&lt;br /&gt;
    Precursor (a_if)&lt;br /&gt;
    if_post_actions.call ([a_if])&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the actual iteration over the AST is done in the ancestor we need only very little code to analyze a class:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {CA_RULE_CHECKING_TASK} -- Execution Commands&lt;br /&gt;
&lt;br /&gt;
  run_on_class (a_class_to_check: CLASS_C)&lt;br /&gt;
      -- Check all rules that have added their agents.&lt;br /&gt;
    local&lt;br /&gt;
      l_ast: CLASS_AS&lt;br /&gt;
    do&lt;br /&gt;
      last_run_successful := False&lt;br /&gt;
      l_ast := a_class_to_check.ast&lt;br /&gt;
      class_pre_actions.call ([l_ast])&lt;br /&gt;
      process_class_as (l_ast)&lt;br /&gt;
      class_post_actions.call ([l_ast])&lt;br /&gt;
      last_run_successful := True&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code analyzes a class for all active ''standard'' rules. &amp;lt;e&amp;gt;class_pre_actions&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;class_post_actions&amp;lt;/e&amp;gt; are action sequences that are identical to those for the AST nodes. &amp;lt;e&amp;gt;process_class_as&amp;lt;/e&amp;gt;, which is implemented in &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt; will recursively visit all relevant AST nodes and execute their action sequences.&lt;br /&gt;
&lt;br /&gt;
== Example: Rule # 71: ''Self-comparison'' ==&lt;br /&gt;
&lt;br /&gt;
We will go through the implementation of rule # 71 (''Self-comparison'') in detail.&lt;br /&gt;
&lt;br /&gt;
The heart of this implementation lies in the feature &amp;lt;e&amp;gt;analyze_self&amp;lt;/e&amp;gt;. There it is tested whether a binary expression is s self-comparison. &amp;lt;e&amp;gt;is_self&amp;lt;/e&amp;gt;, a &amp;lt;e&amp;gt;BOOLEAN&amp;lt;/e&amp;gt; attribute, is set to true if and only if the argument is a comparison between two identical variables.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
analyze_self (a_bin: attached BINARY_AS)&lt;br /&gt;
    -- Is `a_bin' a self-comparison?&lt;br /&gt;
  do&lt;br /&gt;
    is_self := False&lt;br /&gt;
&lt;br /&gt;
    if&lt;br /&gt;
      attached {EXPR_CALL_AS} a_bin.left as l_e1&lt;br /&gt;
      and then attached {ACCESS_ID_AS} l_e1.call as l_l&lt;br /&gt;
      and then attached {EXPR_CALL_AS} a_bin.right as l_e2&lt;br /&gt;
      and then attached {ACCESS_ID_AS} l_e2.call as l_r&lt;br /&gt;
    then&lt;br /&gt;
      is_self := l_l.feature_name.is_equal (l_r.feature_name)&lt;br /&gt;
      self_name := l_l.access_name_32&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
is_self: BOOLEAN&lt;br /&gt;
    -- Is `a_bin' from last call to `analyze_self' a self-comparison?&lt;br /&gt;
&lt;br /&gt;
self_name: detachable STRING_32&lt;br /&gt;
    -- Name of the self-compared variable.&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both sides of the comparison, &amp;lt;e&amp;gt;a_bin.left&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;a_bin.right&amp;lt;/e&amp;gt;, are tested to have the types that indicate that they are variable or feature accesses. If the tests succeed then &amp;lt;e&amp;gt;is_self&amp;lt;/e&amp;gt; is set according to the equality of the two feature names. Then the name is stored in an internal attribute.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;analyze_self&amp;lt;/e&amp;gt; is used in &amp;lt;e&amp;gt;process_comparison&amp;lt;/e&amp;gt;, which creates a rule violation if a self-comparison was detected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_comparison (a_comparison: BINARY_AS)&lt;br /&gt;
    -- Checks `a_comparison' for rule violations.&lt;br /&gt;
  local&lt;br /&gt;
    l_viol: CA_RULE_VIOLATION&lt;br /&gt;
  do&lt;br /&gt;
    if not in_loop then&lt;br /&gt;
      analyze_self (a_comparison)&lt;br /&gt;
      if is_self then&lt;br /&gt;
        create l_viol.make_with_rule (Current)&lt;br /&gt;
        l_viol.set_location (a_comparison.start_location)&lt;br /&gt;
        l_viol.long_description_info.extend (self_name)&lt;br /&gt;
        violations.extend (l_viol)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First we check that we are not dealing with a loop condition. Self-comparisons in loop conditions are more dangerous and need special treatment (see below). For the rule violation, we set the location to the start location of the binary comparison. We add the variable or feature name to the violation.&lt;br /&gt;
&lt;br /&gt;
Different kinds of comparisons also have different types in the AST. That is why in an AST iterator they are processed independently. Thus, we need to add some delegation to each of the actions that are called when processing a comparison.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_bin_eq (a_bin_eq: BIN_EQ_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_eq)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_ge (a_bin_ge: BIN_GE_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_ge)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_gt (a_bin_gt: BIN_GT_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_gt)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_le (a_bin_le: BIN_LE_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_le)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_lt (a_bin_lt: BIN_LT_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_lt)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the case that a loop condition is a self-comparison, the loop is either never entered or it is never exited. The last case is more severe; the first case only arises with an equality comparison. For this reason we analyze loop conditions separately. If we find such a violation we set &amp;lt;e&amp;gt;in_loop&amp;lt;/e&amp;gt; to &amp;lt;e&amp;gt;True&amp;lt;/e&amp;gt; so that any further self-comparisons are ignored until we have left the loop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
pre_process_loop (a_loop: LOOP_AS)&lt;br /&gt;
    -- Checking a loop `a_loop' for self-comparisons needs more work. If the until expression&lt;br /&gt;
    -- is a self-comparison that does not compare for equality then the loop will&lt;br /&gt;
    -- not terminate, which is more severe consequence compared to other self-comparisons.&lt;br /&gt;
  local&lt;br /&gt;
    l_viol: CA_RULE_VIOLATION&lt;br /&gt;
  do&lt;br /&gt;
    if attached {BINARY_AS} a_loop.stop as l_bin then&lt;br /&gt;
    analyze_self (l_bin)&lt;br /&gt;
    if is_self then&lt;br /&gt;
      create l_viol.make_with_rule (Current)&lt;br /&gt;
      l_viol.set_location (a_loop.stop.start_location)&lt;br /&gt;
      l_viol.long_description_info.extend (self_name)&lt;br /&gt;
      if not attached {BIN_EQ_AS} l_bin then&lt;br /&gt;
          -- It is only a dangerous loop stop condition if we do not have&lt;br /&gt;
          -- an equality comparison.&lt;br /&gt;
        l_viol.long_description_info.extend (&amp;quot;loop_stop&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      violations.extend (l_viol)&lt;br /&gt;
      in_loop := True&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;format_violation_description&amp;lt;/e&amp;gt;, which is declared in &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt; as &amp;lt;e&amp;gt;deferred&amp;lt;/e&amp;gt;, must be implemented. Here, together with a predefined localized text, we mention the name of the self-compared variable. If the self-comparison is located in a loop stop condition we add an additional warning text.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
  local&lt;br /&gt;
    l_info: LINKED_LIST [ANY]&lt;br /&gt;
  do&lt;br /&gt;
    l_info := a_violation.long_description_info&lt;br /&gt;
    a_formatter.add (&amp;quot;'&amp;quot;)&lt;br /&gt;
    if l_info.count &amp;gt;= 1 and then attached {STRING_32} l_info.first as l_name then&lt;br /&gt;
      a_formatter.add_local (l_name)&lt;br /&gt;
    end&lt;br /&gt;
    a_formatter.add (ca_messages.self_comparison_violation_1)&lt;br /&gt;
&lt;br /&gt;
    l_info.compare_objects&lt;br /&gt;
    if l_info.has (&amp;quot;loop_stop&amp;quot;) then&lt;br /&gt;
        -- Dangerous loop stop condition.&lt;br /&gt;
      a_formatter.add (ca_messages.self_comparison_violation_2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we must implement the usual properties.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
title: STRING_32&lt;br /&gt;
  do&lt;br /&gt;
    Result := ca_names.self_comparison_title&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
id: STRING_32 = &amp;quot;CA071&amp;quot;&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
&lt;br /&gt;
description: STRING_32&lt;br /&gt;
  do&lt;br /&gt;
    Result :=  ca_names.self_comparison_description&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, in the initialization we use the default settings, which can be set by calling &amp;lt;e&amp;gt;{CA_RULE}.make_with_defaults&amp;lt;/e&amp;gt;. To the default severity score we assign a custom value. In &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt; we must add all the agents for processing the loop and comparison nodes of the AST.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {NONE} -- Initialization&lt;br /&gt;
&lt;br /&gt;
  make&lt;br /&gt;
      -- Initialization.&lt;br /&gt;
    do&lt;br /&gt;
      make_with_defaults&lt;br /&gt;
      default_severity_score := 70&lt;br /&gt;
		  end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      a_checker.add_bin_eq_pre_action (agent process_bin_eq)&lt;br /&gt;
      a_checker.add_bin_ge_pre_action (agent process_bin_ge)&lt;br /&gt;
      a_checker.add_bin_gt_pre_action (agent process_bin_gt)&lt;br /&gt;
      a_checker.add_bin_le_pre_action (agent process_bin_le)&lt;br /&gt;
      a_checker.add_bin_lt_pre_action (agent process_bin_lt)&lt;br /&gt;
      a_checker.add_loop_pre_action (agent pre_process_loop)&lt;br /&gt;
      a_checker.add_loop_post_action (agent post_process_loop)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The complete source code of this rule is available in the [https://svn.eiffel.com/eiffelstudio/branches/eth/eve/Src/framework/code_analysis/rules/expressions/ca_self_comparison_rule.e SVN repository].&lt;br /&gt;
&lt;br /&gt;
== Example: Rule # 2: ''Unused argument'' ==&lt;br /&gt;
&lt;br /&gt;
The ''unused argument'' rule processes the ''feature'', ''body'', ''access id'', and ''converted expression'' AST nodes. The feature node is stored for the description and for ignoring ''deferred'' features. The body node is used to retrieve the arguments. The ''access id'' and ''converted expression'' nodes may represent used arguments, so the nodes are used to mark arguments as read. We register the ''pre'' actions for all the AST nodes as well as the ''post'' action for the ''body'' node in &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      a_checker.add_feature_pre_action (agent process_feature)&lt;br /&gt;
      a_checker.add_body_pre_action (agent process_body)&lt;br /&gt;
      a_checker.add_body_post_action (agent post_process_body)&lt;br /&gt;
      a_checker.add_access_id_pre_action (agent process_access_id)&lt;br /&gt;
      a_checker.add_converted_expr_pre_action (agent process_converted_expr)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On processing a feature we store the feature instance, which will be used later.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_feature (a_feature_as: FEATURE_AS)&lt;br /&gt;
    -- Sets the current feature.&lt;br /&gt;
  do&lt;br /&gt;
    current_feature := a_feature_as&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Before processing the body of a feature we store a list of all the argument names. This is however only done if the feature is a routine, if it has arguments, and if it is not external. In the code we need two nested loops since the arguments are grouped by type. For example, two consecutive &amp;lt;e&amp;gt;STRING&amp;lt;/e&amp;gt; arguments as in &amp;lt;e&amp;gt;feature print(first, second: STRING)&amp;lt;/e&amp;gt; are in one entry of &amp;lt;e&amp;gt;{BODY_AS}.arguments&amp;lt;/e&amp;gt;. This single entry is itself a list of arguments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_body (a_body_as: BODY_AS)&lt;br /&gt;
    -- Retrieves the arguments from `a_body_as'.&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    has_arguments := (a_body_as.arguments /= Void)&lt;br /&gt;
    create args_used.make (0)&lt;br /&gt;
    n_arguments := 0&lt;br /&gt;
    if&lt;br /&gt;
      attached a_body_as.as_routine as l_rout&lt;br /&gt;
      and then has_arguments&lt;br /&gt;
      and then not l_rout.is_external&lt;br /&gt;
    then&lt;br /&gt;
      routine_body := a_body_as&lt;br /&gt;
      create arg_names.make (0)&lt;br /&gt;
      across a_body_as.arguments as l_args loop&lt;br /&gt;
        from&lt;br /&gt;
          j := 1&lt;br /&gt;
        until&lt;br /&gt;
          j &amp;gt; l_args.item.id_list.count&lt;br /&gt;
        loop&lt;br /&gt;
          arg_names.extend (l_args.item.item_name (j))&lt;br /&gt;
          args_used.extend (False)&lt;br /&gt;
          n_arguments := n_arguments + 1&lt;br /&gt;
          j := j + 1&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
has_arguments: BOOLEAN&lt;br /&gt;
    -- Does current feature have arguments?&lt;br /&gt;
&lt;br /&gt;
current_feature: FEATURE_AS&lt;br /&gt;
    -- Currently checked feature.&lt;br /&gt;
&lt;br /&gt;
routine_body: BODY_AS&lt;br /&gt;
    -- Current routine body.&lt;br /&gt;
&lt;br /&gt;
n_arguments: INTEGER&lt;br /&gt;
    -- # arguments for current routine.&lt;br /&gt;
&lt;br /&gt;
arg_names: ARRAYED_LIST [STRING_32]&lt;br /&gt;
    -- Argument names of current routine.&lt;br /&gt;
&lt;br /&gt;
args_used: ARRAYED_LIST [BOOLEAN]&lt;br /&gt;
    -- Which argument has been used?&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both the nodes &amp;lt;e&amp;gt;{ACCESS_ID_AS}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{CONVERTED_EXPR_AS}&amp;lt;/e&amp;gt; may represent used arguments. &amp;lt;e&amp;gt;{ACCESS_ID_AS}&amp;lt;/e&amp;gt; is a usual variable usage, while &amp;lt;e&amp;gt;{CONVERTED_EXPR_AS}&amp;lt;/e&amp;gt; stands for an argument used in inline C code (the dollar sign syntax: &amp;lt;e&amp;gt;$arg&amp;lt;/e&amp;gt;). In both routines &amp;lt;e&amp;gt;check_arguments&amp;lt;/e&amp;gt; is called eventually, which updates the internal data structures of our rule class.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_access_id (a_aid: ACCESS_ID_AS)&lt;br /&gt;
    -- Checks if `a_aid' is an argument.&lt;br /&gt;
  do&lt;br /&gt;
    check_arguments (a_aid.feature_name.name_32)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_converted_expr (a_conv: CONVERTED_EXPR_AS)&lt;br /&gt;
    -- Checks if `a_conv' is an argument used in the&lt;br /&gt;
    -- form `$arg'.&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    if&lt;br /&gt;
      attached {ADDRESS_AS} a_conv.expr as l_address&lt;br /&gt;
      and then attached {FEAT_NAME_ID_AS} l_address.feature_name as l_id&lt;br /&gt;
    then&lt;br /&gt;
      check_arguments (l_id.feature_name.name_32)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
check_arguments (a_var_name: attached STRING_32)&lt;br /&gt;
    -- Mark an argument as used if it corresponds to `a_aid'.&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    from&lt;br /&gt;
      j := 1&lt;br /&gt;
    until&lt;br /&gt;
      j &amp;gt; n_arguments&lt;br /&gt;
    loop&lt;br /&gt;
      if not args_used [j] and then arg_names [j].is_equal (a_var_name) then&lt;br /&gt;
        args_used [j] := True&lt;br /&gt;
      end&lt;br /&gt;
      j := j + 1&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;post_process_body&amp;lt;/e&amp;gt; finally checks if there exist unused arguments. If this is the case then all the relevant variable names are stored in the rule violation. Also, the feature is stored (for the feature name). The location of the violation is set to the start of the routine body. No rule violation is issued if the feature is deferred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
post_process_body (a_body: BODY_AS)&lt;br /&gt;
    -- Adds a violation if the feature contains unused arguments.&lt;br /&gt;
  local&lt;br /&gt;
    l_violation: CA_RULE_VIOLATION&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    if&lt;br /&gt;
      a_body.content /= Void&lt;br /&gt;
      and then not current_feature.is_deferred&lt;br /&gt;
      and then has_arguments&lt;br /&gt;
      and then args_used.has (False)&lt;br /&gt;
    then&lt;br /&gt;
      create l_violation.make_with_rule (Current)&lt;br /&gt;
      l_violation.set_location (routine_body.start_location)&lt;br /&gt;
      l_violation.long_description_info.extend (current_feature)&lt;br /&gt;
      from&lt;br /&gt;
        j := 1&lt;br /&gt;
      until&lt;br /&gt;
        j &amp;gt; n_arguments&lt;br /&gt;
      loop&lt;br /&gt;
        if not args_used.at (j) then&lt;br /&gt;
          l_violation.long_description_info.extend (arg_names.at (j))&lt;br /&gt;
        end&lt;br /&gt;
        j := j + 1&lt;br /&gt;
      end&lt;br /&gt;
      violations.extend (l_violation)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All the information that was stored in the rule violation is used for the formatted description:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    a_formatter.add (ca_messages.unused_argument_violation_1)&lt;br /&gt;
    from&lt;br /&gt;
      j := 2&lt;br /&gt;
    until&lt;br /&gt;
      j &amp;gt; a_violation.long_description_info.count&lt;br /&gt;
    loop&lt;br /&gt;
      if j &amp;gt; 2 then a_formatter.add (&amp;quot;, &amp;quot;) end&lt;br /&gt;
      a_formatter.add (&amp;quot;'&amp;quot;)&lt;br /&gt;
      if attached {STRING_32} a_violation.long_description_info.at (j) as l_arg then&lt;br /&gt;
        a_formatter.add_local (l_arg)&lt;br /&gt;
      end&lt;br /&gt;
      a_formatter.add (&amp;quot;'&amp;quot;)&lt;br /&gt;
      j := j + 1&lt;br /&gt;
    end&lt;br /&gt;
    a_formatter.add (ca_messages.unused_argument_violation_2)&lt;br /&gt;
    if attached {FEATURE_AS} a_violation.long_description_info.first as l_feature then&lt;br /&gt;
      a_formatter.add_feature_name (l_feature.feature_name.name_32, a_violation.affected_class)&lt;br /&gt;
    end&lt;br /&gt;
    a_formatter.add (ca_messages.unused_argument_violation_3)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The complete source code of this rule is available in the [https://svn.eiffel.com/eiffelstudio/branches/eth/eve/Src/framework/code_analysis/rules/features/ca_unused_argument_rule.e SVN repository].&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15104</id>
		<title>CA UI Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15104"/>
				<updated>2014-03-11T12:24:53Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* Graphical User Interface */ + Example Command&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Library Implementation|&amp;amp;lt;&amp;amp;lt; 7. Library Implementation]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
The classes of the graphical user interface of the code analyzer are all located in the ''interface'' cluster of ''EVE'', in the subfolder ''graphical &amp;gt; tools &amp;gt; code_analysis''. Here is a short overview of what the single classes do:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL}&amp;lt;/e&amp;gt; : Represents the code analysis GUI tool. Contains the tool title and icon, otherwise not much interesting stuff.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL_PANEL}&amp;lt;/e&amp;gt; : The graphical panel for the code analysis tool. It contains buttons, labels, the rule violations table view, and other user interface elements.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; : 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_BENCH_HELPER}&amp;lt;/e&amp;gt; : A helper class for the integration of the code analysis tool. It contains shared instances of &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;, which are used by the GUI.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_SHOW_PREFERENCES_COMMAND}&amp;lt;/e&amp;gt; : The command is used by the ''Preferences'' button in the panel.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_FIX_EXECUTOR}&amp;lt;/e&amp;gt; : This class [[User:Stefan/Code Analysis/Using Analysis Results#Fixing Rule Violations|fixes]] a rule violation that has been found by the code analysis tool.&lt;br /&gt;
&lt;br /&gt;
These are roughly the class relations for the code analysis GUI:&lt;br /&gt;
[[File:CA GUI Diagram.png|thumb|center|650px|The most interesting class relations of the code analysis GUI.]]&lt;br /&gt;
&lt;br /&gt;
=== Caching ===&lt;br /&gt;
&lt;br /&gt;
It is a common case that GUI users run the code analyzer again after having made some changes to the code. We do not need to analyze the same unchanged code again and again. Therefore code analysis caches the results in memory. This only applies to the GUI mode.&lt;br /&gt;
&lt;br /&gt;
Code analysis uses cached results exactly in one case: when the whole system is analyzed and the previous analysis was on the whole system, too.&lt;br /&gt;
&lt;br /&gt;
The caching functionality is implemented in &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;. When the command for analyzing the system is executed, the timestamps of the last modification of the classes are stored in &amp;lt;e&amp;gt;analysis_timestamp : HASH_TABLE [INTEGER, CLASS_I]&amp;lt;/e&amp;gt; before the analysis. Note that the cached results (the rule violations) themselves are managed by &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt;. The only difference to a non-cached analysis is that the rule violations are not deleted by &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; before the next analysis. Then, in case the next command is also for analyzing the whole system, the current timestamps are compared to the stored timestamps. Any class that has been changed in the meantime will be analyzed again; for any unchanged class the rule violations are taken from the cache.&lt;br /&gt;
&lt;br /&gt;
=== Example Command: Analyze One Class ===&lt;br /&gt;
&lt;br /&gt;
We will now roughly go through the code that is executed on the GUI part when the user wants to analyze a single class. As mentioned in Chapter [[User:Stefan/Code Analysis/Running the Analyzer|Running the Analyzer]], this can be done using the class context menu or by dropping the class stone on the button ''Analyze Item''.&lt;br /&gt;
&lt;br /&gt;
In any case &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}.execute_with_stone&amp;lt;/e&amp;gt; is called, which delegates to &amp;lt;e&amp;gt;execute_with_stone_content&amp;lt;/e&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
execute_with_stone (a_stone: STONE)&lt;br /&gt;
    -- Execute with `a_stone'.&lt;br /&gt;
  do&lt;br /&gt;
    execute_with_stone_content (a_stone, Void)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
execute_with_stone_content (a_stone: STONE; a_content: SD_CONTENT)&lt;br /&gt;
    -- Execute with `a_stone'.&lt;br /&gt;
  local&lt;br /&gt;
    l_save_confirm: ES_DISCARDABLE_COMPILE_SAVE_FILES_PROMPT&lt;br /&gt;
    l_classes: DS_ARRAYED_LIST [CLASS_I]&lt;br /&gt;
  do&lt;br /&gt;
      -- Show the tool right from the start.&lt;br /&gt;
    show_ca_tool&lt;br /&gt;
&lt;br /&gt;
    if not eiffel_project.is_compiling then&lt;br /&gt;
      if window_manager.has_modified_windows then&lt;br /&gt;
        create l_classes.make_default&lt;br /&gt;
        window_manager.all_modified_classes.do_all (agent l_classes.force_last)&lt;br /&gt;
        create l_save_confirm.make (l_classes)&lt;br /&gt;
        l_save_confirm.set_button_action (l_save_confirm.dialog_buttons.yes_button, agent save_compile_and_analyze (a_stone))&lt;br /&gt;
        l_save_confirm.set_button_action (l_save_confirm.dialog_buttons.no_button, agent compile_and_analyze (a_stone))&lt;br /&gt;
        l_save_confirm.show_on_active_window&lt;br /&gt;
      else&lt;br /&gt;
        compile_and_analyze (a_stone)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there are modified, unsaved windows a save confirmation dialog is displayed. Eventually program flow passes on to &amp;lt;e&amp;gt;compile_and_analyze&amp;lt;/e&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
compile_and_analyze (a_stone: STONE)&lt;br /&gt;
    -- Compile project and perform analysis of stone `a_stone'.&lt;br /&gt;
  local&lt;br /&gt;
    l_helper: ES_CODE_ANALYSIS_BENCH_HELPER&lt;br /&gt;
    l_dialog: ES_INFORMATION_PROMPT&lt;br /&gt;
  do&lt;br /&gt;
      -- Compile the project and only analyze if the compilation was successful.&lt;br /&gt;
    eiffel_project.quick_melt (True, True, True)&lt;br /&gt;
    if eiffel_project.successful then&lt;br /&gt;
      create l_helper&lt;br /&gt;
      if l_helper.code_analyzer.is_running then&lt;br /&gt;
        create l_dialog.make_standard (ca_messages.already_running_long)&lt;br /&gt;
        l_dialog.show_on_active_window&lt;br /&gt;
      else&lt;br /&gt;
        perform_analysis (a_stone)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;eiffel_project.quick_melt&amp;lt;/e&amp;gt; starts the compilation. A successful compilation is required for code analysis; otherwise nothing is analyzed. After compilation has succeeded we check if code analysis is already running. If this is the case then a dialog is displayed. If on the other hand this last possible obstacle is not present we finally start analyzing by calling &amp;lt;e&amp;gt;perform_analysis&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
perform_analysis (a_stone: STONE)&lt;br /&gt;
    -- Analyze `a_stone' only.&lt;br /&gt;
  local&lt;br /&gt;
    l_helper: ES_CODE_ANALYSIS_BENCH_HELPER&lt;br /&gt;
    l_scope_label: EV_LABEL&lt;br /&gt;
  do&lt;br /&gt;
      -- For simplicity let us assume that `a_stone' does not&lt;br /&gt;
      -- correspond to the system or is equivalent to it.&lt;br /&gt;
    last_was_analyze_all := False&lt;br /&gt;
&lt;br /&gt;
    create l_helper&lt;br /&gt;
    code_analyzer := l_helper.code_analyzer&lt;br /&gt;
    code_analyzer.clear_classes_to_analyze&lt;br /&gt;
    code_analyzer.rule_violations.wipe_out&lt;br /&gt;
&lt;br /&gt;
    l_scope_label := ca_tool.panel.scope_label&lt;br /&gt;
&lt;br /&gt;
    if attached {CLASSC_STONE} a_stone as s then&lt;br /&gt;
      code_analyzer.add_class (s.class_i.config_class)&lt;br /&gt;
      l_scope_label.set_text (s.class_name)&lt;br /&gt;
      l_scope_label.set_foreground_color (create {EV_COLOR}.make_with_8_bit_rgb (140, 140, 255))&lt;br /&gt;
      l_scope_label.set_pebble (s)&lt;br /&gt;
      l_scope_label.set_pick_and_drop_mode&lt;br /&gt;
      l_scope_label.set_tooltip (ca_messages.class_scope_tooltip)&lt;br /&gt;
    elseif [...]&lt;br /&gt;
    [...]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    disable_tool_button&lt;br /&gt;
    window_manager.display_message (ca_messages.status_bar_running)&lt;br /&gt;
    code_analyzer.add_completed_action (agent analysis_completed)&lt;br /&gt;
    code_analyzer.analyze&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The code that deals with stones other than classes is omitted.)&lt;br /&gt;
&lt;br /&gt;
At the start of the routine the code analyzer instance is retrieved from the helper class. All classes that may have been addedbefore, are removed. All previous rule violations are removed as well. The if clause creates a stone for the ''Last Scope'' label in the graphical panel. Then, the button in the tool is disabled so that starting another analysis is prevented until the current one has completed. Finally, the analysis is started. As soon as the analysis has completed &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}.analysis_completed&amp;lt;/e&amp;gt; is called. In this procedure the rule violations (and possibly the exceptions) are retrieved from the code analyzer and displayed in the list in the tool panel.&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;br /&gt;
&lt;br /&gt;
The whole command-line functionality of the code analyzer is located in the class &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. It is located in the ''tty'' cluster of ''EVE''. &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt; is invoked by &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the root class for the ''batch'' (command-line) version of EiffelStudio. In &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the invocation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
elseif option.is_equal (&amp;quot;-code-analysis&amp;quot;) then&lt;br /&gt;
  l_at_args := arguments_in_range (current_option + 1, argument_count)&lt;br /&gt;
  current_option := argument_count + 1&lt;br /&gt;
  create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any command-line arguments after ''-code-analysis'' are passed on to &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. This class, in its creation procedure, processes the arguments as described in [[User:Stefan/Code_Analysis/Command Line Usage|Command Line Usage]]. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure &amp;lt;e&amp;gt;execute&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; of course uses the ''code_analysis'' library and the previously described interface of &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;. After analysis a list of rule violations is output to the command-line. In the code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
across l_code_analyzer.rule_violations as l_vlist loop&lt;br /&gt;
  if not l_vlist.item.is_empty then&lt;br /&gt;
    l_has_violations := True&lt;br /&gt;
      -- Always sort the rule violations by the class they are referring to.&lt;br /&gt;
    output_window.add (ca_messages.cmd_class + l_vlist.key.name + &amp;quot;':%N&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting.&lt;br /&gt;
    across l_vlist.item as ic loop&lt;br /&gt;
      l_rule_name := ic.item.rule.title&lt;br /&gt;
      l_rule_id := ic.item.rule.id&lt;br /&gt;
      if attached ic.item.location as l_loc then&lt;br /&gt;
        l_line := ic.item.location.line.out&lt;br /&gt;
        l_col := ic.item.location.column.out&lt;br /&gt;
        output_window.add (&amp;quot;  (&amp;quot; + l_line + &amp;quot;:&amp;quot; + l_col + &amp;quot;): &amp;quot;&lt;br /&gt;
          + l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      else -- No location attached. Print without location.&lt;br /&gt;
        output_window.add (&amp;quot;  &amp;quot;	+ l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      ic.item.format_violation_description (output_window)&lt;br /&gt;
      output_window.add (&amp;quot;%N&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not l_has_violations then output_window.add (ca_messages.no_issues + &amp;quot;%N&amp;quot;) end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15103</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15103"/>
				<updated>2014-03-11T11:52:53Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* Example: Rule # 2: Unused argument */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] | [[User:Stefan/Code Analysis/UI Implementation|8. UI Implementation &amp;amp;gt; &amp;amp;gt;]]&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# The framework—by far the largest part, with the rule checking, the rules, the control flow graph functionality, and more—is represented as a ''library'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
The whole '''code analysis framework''' is located in the '''library ''code_analysis'''''.&lt;br /&gt;
&lt;br /&gt;
== Class Relations ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows an overview of the relations between the classes of the code analysis framework. All classes are located in the ''code_analysis'' library except for &amp;lt;e&amp;gt;CLASS_C&amp;lt;/e&amp;gt; (EiffelStudio), &amp;lt;e&amp;gt;ROTA_TIMED_TASK_I&amp;lt;/e&amp;gt; (''ecosystem'' cluster), &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; (command-line interface), and &amp;lt;e&amp;gt;ES_CODE_ANALYSIS_BENCH_HELPER&amp;lt;/e&amp;gt; (GUI).&lt;br /&gt;
&lt;br /&gt;
[[File:CA Framework Diagram.png|thumb|center|800px|The most interesting classes of the code analysis framework.]]&lt;br /&gt;
&lt;br /&gt;
== Interface ==&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Rule checking ==&lt;br /&gt;
&lt;br /&gt;
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'', &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;. In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt; this task (&amp;lt;e&amp;gt;l_task&amp;lt;/e&amp;gt;) is invoked as follows:&lt;br /&gt;
&lt;br /&gt;
=== In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed)&lt;br /&gt;
l_task.set_output_actions (output_actions)&lt;br /&gt;
rota.run_task (l_task)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; essentially runs the whole analysis. Like all other conformants to &amp;lt;e&amp;gt;{ROTA_TASK_I}&amp;lt;/e&amp;gt; this class executes a series of ''steps'' between which the user interface gets some time to process its events. In &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; each step analyses one class. This means that a class is checked by ''all'' the rules for violations. The following code does that:&lt;br /&gt;
&lt;br /&gt;
=== From &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
step&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
  do&lt;br /&gt;
    if has_next_step then&lt;br /&gt;
        -- Gather type information&lt;br /&gt;
      type_recorder.clear&lt;br /&gt;
      type_recorder.analyze_class (classes.item)&lt;br /&gt;
      context.set_node_types (type_recorder.node_types)&lt;br /&gt;
      context.set_checking_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      across rules as l_rules loop&lt;br /&gt;
          -- If rule is non-standard then it will not be checked by l_rules_checker.&lt;br /&gt;
          -- We will have the rule check the current class here:&lt;br /&gt;
        if&lt;br /&gt;
          l_rules.item.is_enabled.value&lt;br /&gt;
          and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule&lt;br /&gt;
        then&lt;br /&gt;
          l_cfg_rule.check_class (classes.item)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
        -- Status output.&lt;br /&gt;
      if output_actions /= Void then&lt;br /&gt;
        output_actions.call ([ca_messages.analyzing_class (classes.item.name)])&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      rules_checker.run_on_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      classes.forth&lt;br /&gt;
      has_next_step := not classes.after&lt;br /&gt;
      if not has_next_step then&lt;br /&gt;
        completed_action.call ([exceptions])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  rescue&lt;br /&gt;
      -- Instant error output.&lt;br /&gt;
    if output_actions /= Void then&lt;br /&gt;
      output_actions.call ([ca_messages.error_on_class (classes.item.name)])&lt;br /&gt;
    end&lt;br /&gt;
    exceptions.extend ([exception_manager.last_exception, classes.item])&lt;br /&gt;
      -- Jump to the next class.&lt;br /&gt;
    classes.forth&lt;br /&gt;
    has_next_step := not classes.after&lt;br /&gt;
    if not has_next_step then&lt;br /&gt;
      completed_action.call ([exceptions])&lt;br /&gt;
    end&lt;br /&gt;
    retry&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;type_recorder&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_AST_TYPE_RECORDER}&amp;lt;/e&amp;gt;. 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. &amp;lt;e&amp;gt;context&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;e&amp;gt;across&amp;lt;/e&amp;gt; loop only checks ''control flow graph rules''. All the ''standard'' rules are checked by the line &amp;lt;e&amp;gt;rules_checker.run_on_class (classes.item)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;rules_checker&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt;. This is the class where each rule must register the AST nodes the rule visits. &amp;lt;e&amp;gt;run_on_class&amp;lt;/e&amp;gt; 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. &amp;lt;e&amp;gt;step&amp;lt;/e&amp;gt; is executed repeatedly until there are no classes left to analyze.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;e&amp;gt;rescue&amp;lt;/e&amp;gt; clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.&lt;br /&gt;
&lt;br /&gt;
=== Checking ''Standard'' Rules ===&lt;br /&gt;
&lt;br /&gt;
The relatively large class &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; is responsible for checking ''standard rules''. It does this in a straightforward way. It is a subclass of &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt;, a realization of a visitor on the AST.&lt;br /&gt;
&lt;br /&gt;
Rules can register their actions with &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; by calling a procedure like &amp;lt;e&amp;gt;add_bin_lt_pre_action (a_action: attached PROCEDURE [ANY, TUPLE [BIN_LT_AS]])&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&amp;lt;/e&amp;gt;. These &amp;quot;pre&amp;quot; and &amp;quot;post&amp;quot; actions exist for many other types of AST nodes as well. All the registered actions are stored in &amp;lt;e&amp;gt;ACTION_SEQUENCE&amp;lt;/e&amp;gt; variables:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
if_pre_actions, if_post_actions: ACTION_SEQUENCE [TUPLE [IF_AS]]&lt;br /&gt;
&lt;br /&gt;
add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&lt;br /&gt;
  do&lt;br /&gt;
    if_post_actions.extend (a_action)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding visitor procedures are redefined. This is done is the following way:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_if_as (a_if: IF_AS)&lt;br /&gt;
  do&lt;br /&gt;
    if_pre_actions.call ([a_if])&lt;br /&gt;
    Precursor (a_if)&lt;br /&gt;
    if_post_actions.call ([a_if])&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the actual iteration over the AST is done in the ancestor we need only very little code to analyze a class:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {CA_RULE_CHECKING_TASK} -- Execution Commands&lt;br /&gt;
&lt;br /&gt;
  run_on_class (a_class_to_check: CLASS_C)&lt;br /&gt;
      -- Check all rules that have added their agents.&lt;br /&gt;
    local&lt;br /&gt;
      l_ast: CLASS_AS&lt;br /&gt;
    do&lt;br /&gt;
      last_run_successful := False&lt;br /&gt;
      l_ast := a_class_to_check.ast&lt;br /&gt;
      class_pre_actions.call ([l_ast])&lt;br /&gt;
      process_class_as (l_ast)&lt;br /&gt;
      class_post_actions.call ([l_ast])&lt;br /&gt;
      last_run_successful := True&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code analyzes a class for all active ''standard'' rules. &amp;lt;e&amp;gt;class_pre_actions&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;class_post_actions&amp;lt;/e&amp;gt; are action sequences that are identical to those for the AST nodes. &amp;lt;e&amp;gt;process_class_as&amp;lt;/e&amp;gt;, which is implemented in &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt; will recursively visit all relevant AST nodes and execute their action sequences.&lt;br /&gt;
&lt;br /&gt;
== Example: Rule # 71: ''Self-comparison'' ==&lt;br /&gt;
&lt;br /&gt;
We will go through the implementation of rule # 71 (''Self-comparison'') in detail.&lt;br /&gt;
&lt;br /&gt;
The heart of this implementation lies in the feature &amp;lt;e&amp;gt;analyze_self&amp;lt;/e&amp;gt;. There it is tested whether a binary expression is s self-comparison. &amp;lt;e&amp;gt;is_self&amp;lt;/e&amp;gt;, a &amp;lt;e&amp;gt;BOOLEAN&amp;lt;/e&amp;gt; attribute, is set to true if and only if the argument is a comparison between two identical variables.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
analyze_self (a_bin: attached BINARY_AS)&lt;br /&gt;
    -- Is `a_bin' a self-comparison?&lt;br /&gt;
  do&lt;br /&gt;
    is_self := False&lt;br /&gt;
&lt;br /&gt;
    if&lt;br /&gt;
      attached {EXPR_CALL_AS} a_bin.left as l_e1&lt;br /&gt;
      and then attached {ACCESS_ID_AS} l_e1.call as l_l&lt;br /&gt;
      and then attached {EXPR_CALL_AS} a_bin.right as l_e2&lt;br /&gt;
      and then attached {ACCESS_ID_AS} l_e2.call as l_r&lt;br /&gt;
    then&lt;br /&gt;
      is_self := l_l.feature_name.is_equal (l_r.feature_name)&lt;br /&gt;
      self_name := l_l.access_name_32&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
is_self: BOOLEAN&lt;br /&gt;
    -- Is `a_bin' from last call to `analyze_self' a self-comparison?&lt;br /&gt;
&lt;br /&gt;
self_name: detachable STRING_32&lt;br /&gt;
    -- Name of the self-compared variable.&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both sides of the comparison, &amp;lt;e&amp;gt;a_bin.left&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;a_bin.right&amp;lt;/e&amp;gt;, are tested to have the types that indicate that they are variable or feature accesses. If the tests succeed then &amp;lt;e&amp;gt;is_self&amp;lt;/e&amp;gt; is set according to the equality of the two feature names. Then the name is stored in an internal attribute.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;analyze_self&amp;lt;/e&amp;gt; is used in &amp;lt;e&amp;gt;process_comparison&amp;lt;/e&amp;gt;, which creates a rule violation if a self-comparison was detected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_comparison (a_comparison: BINARY_AS)&lt;br /&gt;
    -- Checks `a_comparison' for rule violations.&lt;br /&gt;
  local&lt;br /&gt;
    l_viol: CA_RULE_VIOLATION&lt;br /&gt;
  do&lt;br /&gt;
    if not in_loop then&lt;br /&gt;
      analyze_self (a_comparison)&lt;br /&gt;
      if is_self then&lt;br /&gt;
        create l_viol.make_with_rule (Current)&lt;br /&gt;
        l_viol.set_location (a_comparison.start_location)&lt;br /&gt;
        l_viol.long_description_info.extend (self_name)&lt;br /&gt;
        violations.extend (l_viol)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First we check that we are not dealing with a loop condition. Self-comparisons in loop conditions are more dangerous and need special treatment (see below). For the rule violation, we set the location to the start location of the binary comparison. We add the variable or feature name to the violation.&lt;br /&gt;
&lt;br /&gt;
Different kinds of comparisons also have different types in the AST. That is why in an AST iterator they are processed independently. Thus, we need to add some delegation to each of the actions that are called when processing a comparison.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_bin_eq (a_bin_eq: BIN_EQ_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_eq)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_ge (a_bin_ge: BIN_GE_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_ge)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_gt (a_bin_gt: BIN_GT_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_gt)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_le (a_bin_le: BIN_LE_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_le)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_lt (a_bin_lt: BIN_LT_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_lt)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the case that a loop condition is a self-comparison, the loop is either never entered or it is never exited. The last case is more severe; the first case only arises with an equality comparison. For this reason we analyze loop conditions separately. If we find such a violation we set &amp;lt;e&amp;gt;in_loop&amp;lt;/e&amp;gt; to &amp;lt;e&amp;gt;True&amp;lt;/e&amp;gt; so that any further self-comparisons are ignored until we have left the loop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
pre_process_loop (a_loop: LOOP_AS)&lt;br /&gt;
    -- Checking a loop `a_loop' for self-comparisons needs more work. If the until expression&lt;br /&gt;
    -- is a self-comparison that does not compare for equality then the loop will&lt;br /&gt;
    -- not terminate, which is more severe consequence compared to other self-comparisons.&lt;br /&gt;
  local&lt;br /&gt;
    l_viol: CA_RULE_VIOLATION&lt;br /&gt;
  do&lt;br /&gt;
    if attached {BINARY_AS} a_loop.stop as l_bin then&lt;br /&gt;
    analyze_self (l_bin)&lt;br /&gt;
    if is_self then&lt;br /&gt;
      create l_viol.make_with_rule (Current)&lt;br /&gt;
      l_viol.set_location (a_loop.stop.start_location)&lt;br /&gt;
      l_viol.long_description_info.extend (self_name)&lt;br /&gt;
      if not attached {BIN_EQ_AS} l_bin then&lt;br /&gt;
          -- It is only a dangerous loop stop condition if we do not have&lt;br /&gt;
          -- an equality comparison.&lt;br /&gt;
        l_viol.long_description_info.extend (&amp;quot;loop_stop&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      violations.extend (l_viol)&lt;br /&gt;
      in_loop := True&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;format_violation_description&amp;lt;/e&amp;gt;, which is declared in &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt; as &amp;lt;e&amp;gt;deferred&amp;lt;/e&amp;gt;, must be implemented. Here, together with a predefined localized text, we mention the name of the self-compared variable. If the self-comparison is located in a loop stop condition we add an additional warning text.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
  local&lt;br /&gt;
    l_info: LINKED_LIST [ANY]&lt;br /&gt;
  do&lt;br /&gt;
    l_info := a_violation.long_description_info&lt;br /&gt;
    a_formatter.add (&amp;quot;'&amp;quot;)&lt;br /&gt;
    if l_info.count &amp;gt;= 1 and then attached {STRING_32} l_info.first as l_name then&lt;br /&gt;
      a_formatter.add_local (l_name)&lt;br /&gt;
    end&lt;br /&gt;
    a_formatter.add (ca_messages.self_comparison_violation_1)&lt;br /&gt;
&lt;br /&gt;
    l_info.compare_objects&lt;br /&gt;
    if l_info.has (&amp;quot;loop_stop&amp;quot;) then&lt;br /&gt;
        -- Dangerous loop stop condition.&lt;br /&gt;
      a_formatter.add (ca_messages.self_comparison_violation_2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we must implement the usual properties.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
title: STRING_32&lt;br /&gt;
  do&lt;br /&gt;
    Result := ca_names.self_comparison_title&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
id: STRING_32 = &amp;quot;CA071&amp;quot;&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
&lt;br /&gt;
description: STRING_32&lt;br /&gt;
  do&lt;br /&gt;
    Result :=  ca_names.self_comparison_description&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, in the initialization we use the default settings, which can be set by calling &amp;lt;e&amp;gt;{CA_RULE}.make_with_defaults&amp;lt;/e&amp;gt;. To the default severity score we assign a custom value. In &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt; we must add all the agents for processing the loop and comparison nodes of the AST.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {NONE} -- Initialization&lt;br /&gt;
&lt;br /&gt;
  make&lt;br /&gt;
      -- Initialization.&lt;br /&gt;
    do&lt;br /&gt;
      make_with_defaults&lt;br /&gt;
      default_severity_score := 70&lt;br /&gt;
		  end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      a_checker.add_bin_eq_pre_action (agent process_bin_eq)&lt;br /&gt;
      a_checker.add_bin_ge_pre_action (agent process_bin_ge)&lt;br /&gt;
      a_checker.add_bin_gt_pre_action (agent process_bin_gt)&lt;br /&gt;
      a_checker.add_bin_le_pre_action (agent process_bin_le)&lt;br /&gt;
      a_checker.add_bin_lt_pre_action (agent process_bin_lt)&lt;br /&gt;
      a_checker.add_loop_pre_action (agent pre_process_loop)&lt;br /&gt;
      a_checker.add_loop_post_action (agent post_process_loop)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The complete source code of this rule is available in the [https://svn.eiffel.com/eiffelstudio/branches/eth/eve/Src/framework/code_analysis/rules/expressions/ca_self_comparison_rule.e SVN repository].&lt;br /&gt;
&lt;br /&gt;
== Example: Rule # 2: ''Unused argument'' ==&lt;br /&gt;
&lt;br /&gt;
The ''unused argument'' rule processes the ''feature'', ''body'', ''access id'', and ''converted expression'' AST nodes. The feature node is stored for the description and for ignoring ''deferred'' features. The body node is used to retrieve the arguments. The ''access id'' and ''converted expression'' nodes may represent used arguments, so the nodes are used to mark arguments as read. We register the ''pre'' actions for all the AST nodes as well as the ''post'' action for the ''body'' node in &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      a_checker.add_feature_pre_action (agent process_feature)&lt;br /&gt;
      a_checker.add_body_pre_action (agent process_body)&lt;br /&gt;
      a_checker.add_body_post_action (agent post_process_body)&lt;br /&gt;
      a_checker.add_access_id_pre_action (agent process_access_id)&lt;br /&gt;
      a_checker.add_converted_expr_pre_action (agent process_converted_expr)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On processing a feature we store the feature instance, which will be used later.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_feature (a_feature_as: FEATURE_AS)&lt;br /&gt;
    -- Sets the current feature.&lt;br /&gt;
  do&lt;br /&gt;
    current_feature := a_feature_as&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Before processing the body of a feature we store a list of all the argument names. This is however only done if the feature is a routine, if it has arguments, and if it is not external. In the code we need two nested loops since the arguments are grouped by type. For example, two consecutive &amp;lt;e&amp;gt;STRING&amp;lt;/e&amp;gt; arguments as in &amp;lt;e&amp;gt;feature print(first, second: STRING)&amp;lt;/e&amp;gt; are in one entry of &amp;lt;e&amp;gt;{BODY_AS}.arguments&amp;lt;/e&amp;gt;. This single entry is itself a list of arguments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_body (a_body_as: BODY_AS)&lt;br /&gt;
    -- Retrieves the arguments from `a_body_as'.&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    has_arguments := (a_body_as.arguments /= Void)&lt;br /&gt;
    create args_used.make (0)&lt;br /&gt;
    n_arguments := 0&lt;br /&gt;
    if&lt;br /&gt;
      attached a_body_as.as_routine as l_rout&lt;br /&gt;
      and then has_arguments&lt;br /&gt;
      and then not l_rout.is_external&lt;br /&gt;
    then&lt;br /&gt;
      routine_body := a_body_as&lt;br /&gt;
      create arg_names.make (0)&lt;br /&gt;
      across a_body_as.arguments as l_args loop&lt;br /&gt;
        from&lt;br /&gt;
          j := 1&lt;br /&gt;
        until&lt;br /&gt;
          j &amp;gt; l_args.item.id_list.count&lt;br /&gt;
        loop&lt;br /&gt;
          arg_names.extend (l_args.item.item_name (j))&lt;br /&gt;
          args_used.extend (False)&lt;br /&gt;
          n_arguments := n_arguments + 1&lt;br /&gt;
          j := j + 1&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
has_arguments: BOOLEAN&lt;br /&gt;
    -- Does current feature have arguments?&lt;br /&gt;
&lt;br /&gt;
current_feature: FEATURE_AS&lt;br /&gt;
    -- Currently checked feature.&lt;br /&gt;
&lt;br /&gt;
routine_body: BODY_AS&lt;br /&gt;
    -- Current routine body.&lt;br /&gt;
&lt;br /&gt;
n_arguments: INTEGER&lt;br /&gt;
    -- # arguments for current routine.&lt;br /&gt;
&lt;br /&gt;
arg_names: ARRAYED_LIST [STRING_32]&lt;br /&gt;
    -- Argument names of current routine.&lt;br /&gt;
&lt;br /&gt;
args_used: ARRAYED_LIST [BOOLEAN]&lt;br /&gt;
    -- Which argument has been used?&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both the nodes &amp;lt;e&amp;gt;{ACCESS_ID_AS}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{CONVERTED_EXPR_AS}&amp;lt;/e&amp;gt; may represent used arguments. &amp;lt;e&amp;gt;{ACCESS_ID_AS}&amp;lt;/e&amp;gt; is a usual variable usage, while &amp;lt;e&amp;gt;{CONVERTED_EXPR_AS}&amp;lt;/e&amp;gt; stands for an argument used in inline C code (the dollar sign syntax: &amp;lt;e&amp;gt;$arg&amp;lt;/e&amp;gt;). In both routines &amp;lt;e&amp;gt;check_arguments&amp;lt;/e&amp;gt; is called eventually, which updates the internal data structures of our rule class.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_access_id (a_aid: ACCESS_ID_AS)&lt;br /&gt;
    -- Checks if `a_aid' is an argument.&lt;br /&gt;
  do&lt;br /&gt;
    check_arguments (a_aid.feature_name.name_32)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_converted_expr (a_conv: CONVERTED_EXPR_AS)&lt;br /&gt;
    -- Checks if `a_conv' is an argument used in the&lt;br /&gt;
    -- form `$arg'.&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    if&lt;br /&gt;
      attached {ADDRESS_AS} a_conv.expr as l_address&lt;br /&gt;
      and then attached {FEAT_NAME_ID_AS} l_address.feature_name as l_id&lt;br /&gt;
    then&lt;br /&gt;
      check_arguments (l_id.feature_name.name_32)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
check_arguments (a_var_name: attached STRING_32)&lt;br /&gt;
    -- Mark an argument as used if it corresponds to `a_aid'.&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    from&lt;br /&gt;
      j := 1&lt;br /&gt;
    until&lt;br /&gt;
      j &amp;gt; n_arguments&lt;br /&gt;
    loop&lt;br /&gt;
      if not args_used [j] and then arg_names [j].is_equal (a_var_name) then&lt;br /&gt;
        args_used [j] := True&lt;br /&gt;
      end&lt;br /&gt;
      j := j + 1&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;post_process_body&amp;lt;/e&amp;gt; finally checks if there exist unused arguments. If this is the case then all the relevant variable names are stored in the rule violation. Also, the feature is stored (for the feature name). The location of the violation is set to the start of the routine body. No rule violation is issued if the feature is deferred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
post_process_body (a_body: BODY_AS)&lt;br /&gt;
    -- Adds a violation if the feature contains unused arguments.&lt;br /&gt;
  local&lt;br /&gt;
    l_violation: CA_RULE_VIOLATION&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    if&lt;br /&gt;
      a_body.content /= Void&lt;br /&gt;
      and then not current_feature.is_deferred&lt;br /&gt;
      and then has_arguments&lt;br /&gt;
      and then args_used.has (False)&lt;br /&gt;
    then&lt;br /&gt;
      create l_violation.make_with_rule (Current)&lt;br /&gt;
      l_violation.set_location (routine_body.start_location)&lt;br /&gt;
      l_violation.long_description_info.extend (current_feature)&lt;br /&gt;
      from&lt;br /&gt;
        j := 1&lt;br /&gt;
      until&lt;br /&gt;
        j &amp;gt; n_arguments&lt;br /&gt;
      loop&lt;br /&gt;
        if not args_used.at (j) then&lt;br /&gt;
          l_violation.long_description_info.extend (arg_names.at (j))&lt;br /&gt;
        end&lt;br /&gt;
        j := j + 1&lt;br /&gt;
      end&lt;br /&gt;
      violations.extend (l_violation)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All the information that was stored in the rule violation is used for the formatted description:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
  local&lt;br /&gt;
    j: INTEGER&lt;br /&gt;
  do&lt;br /&gt;
    a_formatter.add (ca_messages.unused_argument_violation_1)&lt;br /&gt;
    from&lt;br /&gt;
      j := 2&lt;br /&gt;
    until&lt;br /&gt;
      j &amp;gt; a_violation.long_description_info.count&lt;br /&gt;
    loop&lt;br /&gt;
      if j &amp;gt; 2 then a_formatter.add (&amp;quot;, &amp;quot;) end&lt;br /&gt;
      a_formatter.add (&amp;quot;'&amp;quot;)&lt;br /&gt;
      if attached {STRING_32} a_violation.long_description_info.at (j) as l_arg then&lt;br /&gt;
        a_formatter.add_local (l_arg)&lt;br /&gt;
      end&lt;br /&gt;
      a_formatter.add (&amp;quot;'&amp;quot;)&lt;br /&gt;
      j := j + 1&lt;br /&gt;
    end&lt;br /&gt;
    a_formatter.add (ca_messages.unused_argument_violation_2)&lt;br /&gt;
    if attached {FEATURE_AS} a_violation.long_description_info.first as l_feature then&lt;br /&gt;
      a_formatter.add_feature_name (l_feature.feature_name.name_32, a_violation.affected_class)&lt;br /&gt;
    end&lt;br /&gt;
    a_formatter.add (ca_messages.unused_argument_violation_3)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The complete source code of this rule is available in the [https://svn.eiffel.com/eiffelstudio/branches/eth/eve/Src/framework/code_analysis/rules/features/ca_unused_argument_rule.e SVN repository].&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15102</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15102"/>
				<updated>2014-03-09T16:37:38Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: Example: Self-comparison&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] | [[User:Stefan/Code Analysis/UI Implementation|8. UI Implementation &amp;amp;gt; &amp;amp;gt;]]&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# The framework—by far the largest part, with the rule checking, the rules, the control flow graph functionality, and more—is represented as a ''library'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
The whole '''code analysis framework''' is located in the '''library ''code_analysis'''''.&lt;br /&gt;
&lt;br /&gt;
== Class Relations ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows an overview of the relations between the classes of the code analysis framework. All classes are located in the ''code_analysis'' library except for &amp;lt;e&amp;gt;CLASS_C&amp;lt;/e&amp;gt; (EiffelStudio), &amp;lt;e&amp;gt;ROTA_TIMED_TASK_I&amp;lt;/e&amp;gt; (''ecosystem'' cluster), &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; (command-line interface), and &amp;lt;e&amp;gt;ES_CODE_ANALYSIS_BENCH_HELPER&amp;lt;/e&amp;gt; (GUI).&lt;br /&gt;
&lt;br /&gt;
[[File:CA Framework Diagram.png|thumb|center|800px|The most interesting classes of the code analysis framework.]]&lt;br /&gt;
&lt;br /&gt;
== Interface ==&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Rule checking ==&lt;br /&gt;
&lt;br /&gt;
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'', &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;. In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt; this task (&amp;lt;e&amp;gt;l_task&amp;lt;/e&amp;gt;) is invoked as follows:&lt;br /&gt;
&lt;br /&gt;
=== In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed)&lt;br /&gt;
l_task.set_output_actions (output_actions)&lt;br /&gt;
rota.run_task (l_task)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; essentially runs the whole analysis. Like all other conformants to &amp;lt;e&amp;gt;{ROTA_TASK_I}&amp;lt;/e&amp;gt; this class executes a series of ''steps'' between which the user interface gets some time to process its events. In &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; each step analyses one class. This means that a class is checked by ''all'' the rules for violations. The following code does that:&lt;br /&gt;
&lt;br /&gt;
=== From &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
step&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
  do&lt;br /&gt;
    if has_next_step then&lt;br /&gt;
        -- Gather type information&lt;br /&gt;
      type_recorder.clear&lt;br /&gt;
      type_recorder.analyze_class (classes.item)&lt;br /&gt;
      context.set_node_types (type_recorder.node_types)&lt;br /&gt;
      context.set_checking_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      across rules as l_rules loop&lt;br /&gt;
          -- If rule is non-standard then it will not be checked by l_rules_checker.&lt;br /&gt;
          -- We will have the rule check the current class here:&lt;br /&gt;
        if&lt;br /&gt;
          l_rules.item.is_enabled.value&lt;br /&gt;
          and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule&lt;br /&gt;
        then&lt;br /&gt;
          l_cfg_rule.check_class (classes.item)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
        -- Status output.&lt;br /&gt;
      if output_actions /= Void then&lt;br /&gt;
        output_actions.call ([ca_messages.analyzing_class (classes.item.name)])&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      rules_checker.run_on_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      classes.forth&lt;br /&gt;
      has_next_step := not classes.after&lt;br /&gt;
      if not has_next_step then&lt;br /&gt;
        completed_action.call ([exceptions])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  rescue&lt;br /&gt;
      -- Instant error output.&lt;br /&gt;
    if output_actions /= Void then&lt;br /&gt;
      output_actions.call ([ca_messages.error_on_class (classes.item.name)])&lt;br /&gt;
    end&lt;br /&gt;
    exceptions.extend ([exception_manager.last_exception, classes.item])&lt;br /&gt;
      -- Jump to the next class.&lt;br /&gt;
    classes.forth&lt;br /&gt;
    has_next_step := not classes.after&lt;br /&gt;
    if not has_next_step then&lt;br /&gt;
      completed_action.call ([exceptions])&lt;br /&gt;
    end&lt;br /&gt;
    retry&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;type_recorder&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_AST_TYPE_RECORDER}&amp;lt;/e&amp;gt;. 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. &amp;lt;e&amp;gt;context&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;e&amp;gt;across&amp;lt;/e&amp;gt; loop only checks ''control flow graph rules''. All the ''standard'' rules are checked by the line &amp;lt;e&amp;gt;rules_checker.run_on_class (classes.item)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;rules_checker&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt;. This is the class where each rule must register the AST nodes the rule visits. &amp;lt;e&amp;gt;run_on_class&amp;lt;/e&amp;gt; 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. &amp;lt;e&amp;gt;step&amp;lt;/e&amp;gt; is executed repeatedly until there are no classes left to analyze.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;e&amp;gt;rescue&amp;lt;/e&amp;gt; clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.&lt;br /&gt;
&lt;br /&gt;
=== Checking ''Standard'' Rules ===&lt;br /&gt;
&lt;br /&gt;
The relatively large class &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; is responsible for checking ''standard rules''. It does this in a straightforward way. It is a subclass of &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt;, a realization of a visitor on the AST.&lt;br /&gt;
&lt;br /&gt;
Rules can register their actions with &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; by calling a procedure like &amp;lt;e&amp;gt;add_bin_lt_pre_action (a_action: attached PROCEDURE [ANY, TUPLE [BIN_LT_AS]])&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&amp;lt;/e&amp;gt;. These &amp;quot;pre&amp;quot; and &amp;quot;post&amp;quot; actions exist for many other types of AST nodes as well. All the registered actions are stored in &amp;lt;e&amp;gt;ACTION_SEQUENCE&amp;lt;/e&amp;gt; variables:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
if_pre_actions, if_post_actions: ACTION_SEQUENCE [TUPLE [IF_AS]]&lt;br /&gt;
&lt;br /&gt;
add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&lt;br /&gt;
  do&lt;br /&gt;
    if_post_actions.extend (a_action)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding visitor procedures are redefined. This is done is the following way:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_if_as (a_if: IF_AS)&lt;br /&gt;
  do&lt;br /&gt;
    if_pre_actions.call ([a_if])&lt;br /&gt;
    Precursor (a_if)&lt;br /&gt;
    if_post_actions.call ([a_if])&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the actual iteration over the AST is done in the ancestor we need only very little code to analyze a class:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {CA_RULE_CHECKING_TASK} -- Execution Commands&lt;br /&gt;
&lt;br /&gt;
  run_on_class (a_class_to_check: CLASS_C)&lt;br /&gt;
      -- Check all rules that have added their agents.&lt;br /&gt;
    local&lt;br /&gt;
      l_ast: CLASS_AS&lt;br /&gt;
    do&lt;br /&gt;
      last_run_successful := False&lt;br /&gt;
      l_ast := a_class_to_check.ast&lt;br /&gt;
      class_pre_actions.call ([l_ast])&lt;br /&gt;
      process_class_as (l_ast)&lt;br /&gt;
      class_post_actions.call ([l_ast])&lt;br /&gt;
      last_run_successful := True&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code analyzes a class for all active ''standard'' rules. &amp;lt;e&amp;gt;class_pre_actions&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;class_post_actions&amp;lt;/e&amp;gt; are action sequences that are identical to those for the AST nodes. &amp;lt;e&amp;gt;process_class_as&amp;lt;/e&amp;gt;, which is implemented in &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt; will recursively visit all relevant AST nodes and execute their action sequences.&lt;br /&gt;
&lt;br /&gt;
== Example: Rule # 71: ''Self-comparison'' ==&lt;br /&gt;
&lt;br /&gt;
We will go through the implementation of rule # 71 (''Self-comparison'') in detail.&lt;br /&gt;
&lt;br /&gt;
The heart of this implementation lies in the feature &amp;lt;e&amp;gt;analyze_self&amp;lt;/e&amp;gt;. There it is tested whether a binary expression is s self-comparison. &amp;lt;e&amp;gt;is_self&amp;lt;/e&amp;gt;, a &amp;lt;e&amp;gt;BOOLEAN&amp;lt;/e&amp;gt; attribute, is set to true if and only if the argument is a comparison between two identical variables.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
analyze_self (a_bin: attached BINARY_AS)&lt;br /&gt;
    -- Is `a_bin' a self-comparison?&lt;br /&gt;
  do&lt;br /&gt;
    is_self := False&lt;br /&gt;
&lt;br /&gt;
    if&lt;br /&gt;
      attached {EXPR_CALL_AS} a_bin.left as l_e1&lt;br /&gt;
      and then attached {ACCESS_ID_AS} l_e1.call as l_l&lt;br /&gt;
      and then attached {EXPR_CALL_AS} a_bin.right as l_e2&lt;br /&gt;
      and then attached {ACCESS_ID_AS} l_e2.call as l_r&lt;br /&gt;
    then&lt;br /&gt;
      is_self := l_l.feature_name.is_equal (l_r.feature_name)&lt;br /&gt;
      self_name := l_l.access_name_32&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
is_self: BOOLEAN&lt;br /&gt;
    -- Is `a_bin' from last call to `analyze_self' a self-comparison?&lt;br /&gt;
&lt;br /&gt;
self_name: detachable STRING_32&lt;br /&gt;
    -- Name of the self-compared variable.&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both sides of the comparison, &amp;lt;e&amp;gt;a_bin.left&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;a_bin.right&amp;lt;/e&amp;gt;, are tested to have the types that indicate that they are variable or feature accesses. If the tests succeed then &amp;lt;e&amp;gt;is_self&amp;lt;/e&amp;gt; is set according to the equality of the two feature names. Then the name is stored in an internal attribute.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;analyze_self&amp;lt;/e&amp;gt; is used in &amp;lt;e&amp;gt;process_comparison&amp;lt;/e&amp;gt;, which creates a rule violation if a self-comparison was detected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_comparison (a_comparison: BINARY_AS)&lt;br /&gt;
    -- Checks `a_comparison' for rule violations.&lt;br /&gt;
  local&lt;br /&gt;
    l_viol: CA_RULE_VIOLATION&lt;br /&gt;
  do&lt;br /&gt;
    if not in_loop then&lt;br /&gt;
      analyze_self (a_comparison)&lt;br /&gt;
      if is_self then&lt;br /&gt;
        create l_viol.make_with_rule (Current)&lt;br /&gt;
        l_viol.set_location (a_comparison.start_location)&lt;br /&gt;
        l_viol.long_description_info.extend (self_name)&lt;br /&gt;
        violations.extend (l_viol)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
First we check that we are not dealing with a loop condition. Self-comparisons in loop conditions are more dangerous and need special treatment (see below). For the rule violation, we set the location to the start location of the binary comparison. We add the variable or feature name to the violation.&lt;br /&gt;
&lt;br /&gt;
Different kinds of comparisons also have different types in the AST. That is why in an AST iterator they are processed independently. Thus, we need to add some delegation to each of the actions that are called when processing a comparison.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_bin_eq (a_bin_eq: BIN_EQ_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_eq)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_ge (a_bin_ge: BIN_GE_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_ge)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_gt (a_bin_gt: BIN_GT_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_gt)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_le (a_bin_le: BIN_LE_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_le)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
process_bin_lt (a_bin_lt: BIN_LT_AS)&lt;br /&gt;
  do&lt;br /&gt;
    process_comparison (a_bin_lt)&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the case that a loop condition is a self-comparison, the loop is either never entered or it is never exited. The last case is more severe; the first case only arises with an equality comparison. For this reason we analyze loop conditions separately. If we find such a violation we set &amp;lt;e&amp;gt;in_loop&amp;lt;/e&amp;gt; to &amp;lt;e&amp;gt;True&amp;lt;/e&amp;gt; so that any further self-comparisons are ignored until we have left the loop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
pre_process_loop (a_loop: LOOP_AS)&lt;br /&gt;
    -- Checking a loop `a_loop' for self-comparisons needs more work. If the until expression&lt;br /&gt;
    -- is a self-comparison that does not compare for equality then the loop will&lt;br /&gt;
    -- not terminate, which is more severe consequence compared to other self-comparisons.&lt;br /&gt;
  local&lt;br /&gt;
    l_viol: CA_RULE_VIOLATION&lt;br /&gt;
  do&lt;br /&gt;
    if attached {BINARY_AS} a_loop.stop as l_bin then&lt;br /&gt;
    analyze_self (l_bin)&lt;br /&gt;
    if is_self then&lt;br /&gt;
      create l_viol.make_with_rule (Current)&lt;br /&gt;
      l_viol.set_location (a_loop.stop.start_location)&lt;br /&gt;
      l_viol.long_description_info.extend (self_name)&lt;br /&gt;
      if not attached {BIN_EQ_AS} l_bin then&lt;br /&gt;
          -- It is only a dangerous loop stop condition if we do not have&lt;br /&gt;
          -- an equality comparison.&lt;br /&gt;
        l_viol.long_description_info.extend (&amp;quot;loop_stop&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      violations.extend (l_viol)&lt;br /&gt;
      in_loop := True&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;format_violation_description&amp;lt;/e&amp;gt;, which is declared in &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt; as &amp;lt;e&amp;gt;deferred&amp;lt;/e&amp;gt;, must be implemented. Here, together with a predefined localized text, we mention the name of the self-compared variable. If the self-comparison is located in a loop stop condition we add an additional warning text.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
  local&lt;br /&gt;
    l_info: LINKED_LIST [ANY]&lt;br /&gt;
  do&lt;br /&gt;
    l_info := a_violation.long_description_info&lt;br /&gt;
    a_formatter.add (&amp;quot;'&amp;quot;)&lt;br /&gt;
    if l_info.count &amp;gt;= 1 and then attached {STRING_32} l_info.first as l_name then&lt;br /&gt;
      a_formatter.add_local (l_name)&lt;br /&gt;
    end&lt;br /&gt;
    a_formatter.add (ca_messages.self_comparison_violation_1)&lt;br /&gt;
&lt;br /&gt;
    l_info.compare_objects&lt;br /&gt;
    if l_info.has (&amp;quot;loop_stop&amp;quot;) then&lt;br /&gt;
        -- Dangerous loop stop condition.&lt;br /&gt;
      a_formatter.add (ca_messages.self_comparison_violation_2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we must implement the usual properties.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
title: STRING_32&lt;br /&gt;
  do&lt;br /&gt;
    Result := ca_names.self_comparison_title&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
id: STRING_32 = &amp;quot;CA071&amp;quot;&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
&lt;br /&gt;
description: STRING_32&lt;br /&gt;
  do&lt;br /&gt;
    Result :=  ca_names.self_comparison_description&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, in the initialization we use the default settings, which can be set by calling &amp;lt;e&amp;gt;{CA_RULE}.make_with_defaults&amp;lt;/e&amp;gt;. To the default severity score we assign a custom value. In &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt; we must add all the agents for processing the loop and comparison nodes of the AST.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {NONE} -- Initialization&lt;br /&gt;
&lt;br /&gt;
  make&lt;br /&gt;
      -- Initialization.&lt;br /&gt;
    do&lt;br /&gt;
      make_with_defaults&lt;br /&gt;
      default_severity_score := 70&lt;br /&gt;
		  end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      a_checker.add_bin_eq_pre_action (agent process_bin_eq)&lt;br /&gt;
      a_checker.add_bin_ge_pre_action (agent process_bin_ge)&lt;br /&gt;
      a_checker.add_bin_gt_pre_action (agent process_bin_gt)&lt;br /&gt;
      a_checker.add_bin_le_pre_action (agent process_bin_le)&lt;br /&gt;
      a_checker.add_bin_lt_pre_action (agent process_bin_lt)&lt;br /&gt;
      a_checker.add_loop_pre_action (agent pre_process_loop)&lt;br /&gt;
      a_checker.add_loop_post_action (agent post_process_loop)&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The complete source code of this rule is available in the [https://svn.eiffel.com/eiffelstudio/branches/eth/eve/Src/framework/code_analysis/rules/expressions/ca_self_comparison_rule.e SVN repository].&lt;br /&gt;
&lt;br /&gt;
== Example: Rule # 2: ''Unused argument'' ==&lt;br /&gt;
&lt;br /&gt;
The complete source code of this rule is available in the [https://svn.eiffel.com/eiffelstudio/branches/eth/eve/Src/framework/code_analysis/rules/features/ca_unused_argument_rule.e SVN repository].&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15101</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15101"/>
				<updated>2014-03-09T14:41:18Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: lang&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] | [[User:Stefan/Code Analysis/UI Implementation|8. UI Implementation &amp;amp;gt; &amp;amp;gt;]]&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# The framework—by far the largest part, with the rule checking, the rules, the control flow graph functionality, and more—is represented as a ''library'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
The whole '''code analysis framework''' is located in the '''library ''code_analysis'''''.&lt;br /&gt;
&lt;br /&gt;
== Class Relations ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows an overview of the relations between the classes of the code analysis framework. All classes are located in the ''code_analysis'' library except for &amp;lt;e&amp;gt;CLASS_C&amp;lt;/e&amp;gt; (EiffelStudio), &amp;lt;e&amp;gt;ROTA_TIMED_TASK_I&amp;lt;/e&amp;gt; (''ecosystem'' cluster), &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; (command-line interface), and &amp;lt;e&amp;gt;ES_CODE_ANALYSIS_BENCH_HELPER&amp;lt;/e&amp;gt; (GUI).&lt;br /&gt;
&lt;br /&gt;
[[File:CA Framework Diagram.png|thumb|center|800px|The most interesting classes of the code analysis framework.]]&lt;br /&gt;
&lt;br /&gt;
== Interface ==&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Rule checking ==&lt;br /&gt;
&lt;br /&gt;
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'', &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;. In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt; this task (&amp;lt;e&amp;gt;l_task&amp;lt;/e&amp;gt;) is invoked as follows:&lt;br /&gt;
&lt;br /&gt;
=== In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed)&lt;br /&gt;
l_task.set_output_actions (output_actions)&lt;br /&gt;
rota.run_task (l_task)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; essentially runs the whole analysis. Like all other conformants to &amp;lt;e&amp;gt;{ROTA_TASK_I}&amp;lt;/e&amp;gt; this class executes a series of ''steps'' between which the user interface gets some time to process its events. In &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; each step analyses one class. This means that a class is checked by ''all'' the rules for violations. The following code does that:&lt;br /&gt;
&lt;br /&gt;
=== From &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
step&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
  do&lt;br /&gt;
    if has_next_step then&lt;br /&gt;
        -- Gather type information&lt;br /&gt;
      type_recorder.clear&lt;br /&gt;
      type_recorder.analyze_class (classes.item)&lt;br /&gt;
      context.set_node_types (type_recorder.node_types)&lt;br /&gt;
      context.set_checking_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      across rules as l_rules loop&lt;br /&gt;
          -- If rule is non-standard then it will not be checked by l_rules_checker.&lt;br /&gt;
          -- We will have the rule check the current class here:&lt;br /&gt;
        if&lt;br /&gt;
          l_rules.item.is_enabled.value&lt;br /&gt;
          and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule&lt;br /&gt;
        then&lt;br /&gt;
          l_cfg_rule.check_class (classes.item)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
        -- Status output.&lt;br /&gt;
      if output_actions /= Void then&lt;br /&gt;
        output_actions.call ([ca_messages.analyzing_class (classes.item.name)])&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      rules_checker.run_on_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      classes.forth&lt;br /&gt;
      has_next_step := not classes.after&lt;br /&gt;
      if not has_next_step then&lt;br /&gt;
        completed_action.call ([exceptions])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  rescue&lt;br /&gt;
      -- Instant error output.&lt;br /&gt;
    if output_actions /= Void then&lt;br /&gt;
      output_actions.call ([ca_messages.error_on_class (classes.item.name)])&lt;br /&gt;
    end&lt;br /&gt;
    exceptions.extend ([exception_manager.last_exception, classes.item])&lt;br /&gt;
      -- Jump to the next class.&lt;br /&gt;
    classes.forth&lt;br /&gt;
    has_next_step := not classes.after&lt;br /&gt;
    if not has_next_step then&lt;br /&gt;
      completed_action.call ([exceptions])&lt;br /&gt;
    end&lt;br /&gt;
    retry&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;type_recorder&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_AST_TYPE_RECORDER}&amp;lt;/e&amp;gt;. 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. &amp;lt;e&amp;gt;context&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;e&amp;gt;across&amp;lt;/e&amp;gt; loop only checks ''control flow graph rules''. All the ''standard'' rules are checked by the line &amp;lt;e&amp;gt;rules_checker.run_on_class (classes.item)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;rules_checker&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt;. This is the class where each rule must register the AST nodes the rule visits. &amp;lt;e&amp;gt;run_on_class&amp;lt;/e&amp;gt; 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. &amp;lt;e&amp;gt;step&amp;lt;/e&amp;gt; is executed repeatedly until there are no classes left to analyze.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;e&amp;gt;rescue&amp;lt;/e&amp;gt; clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.&lt;br /&gt;
&lt;br /&gt;
=== Checking ''Standard'' Rules ===&lt;br /&gt;
&lt;br /&gt;
The relatively large class &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; is responsible for checking ''standard rules''. It does this in a straightforward way. It is a subclass of &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt;, a realization of a visitor on the AST.&lt;br /&gt;
&lt;br /&gt;
Rules can register their actions with &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; by calling a procedure like &amp;lt;e&amp;gt;add_bin_lt_pre_action (a_action: attached PROCEDURE [ANY, TUPLE [BIN_LT_AS]])&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&amp;lt;/e&amp;gt;. These &amp;quot;pre&amp;quot; and &amp;quot;post&amp;quot; actions exist for many other types of AST nodes as well. All the registered actions are stored in &amp;lt;e&amp;gt;ACTION_SEQUENCE&amp;lt;/e&amp;gt; variables:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
if_pre_actions, if_post_actions: ACTION_SEQUENCE [TUPLE [IF_AS]]&lt;br /&gt;
&lt;br /&gt;
add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&lt;br /&gt;
  do&lt;br /&gt;
    if_post_actions.extend (a_action)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding visitor procedures are redefined. This is done is the following way:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_if_as (a_if: IF_AS)&lt;br /&gt;
  do&lt;br /&gt;
    if_pre_actions.call ([a_if])&lt;br /&gt;
    Precursor (a_if)&lt;br /&gt;
    if_post_actions.call ([a_if])&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the actual iteration over the AST is done in the ancestor we need only very little code to analyze a class:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {CA_RULE_CHECKING_TASK} -- Execution Commands&lt;br /&gt;
&lt;br /&gt;
  run_on_class (a_class_to_check: CLASS_C)&lt;br /&gt;
      -- Check all rules that have added their agents.&lt;br /&gt;
    local&lt;br /&gt;
      l_ast: CLASS_AS&lt;br /&gt;
    do&lt;br /&gt;
      last_run_successful := False&lt;br /&gt;
      l_ast := a_class_to_check.ast&lt;br /&gt;
      class_pre_actions.call ([l_ast])&lt;br /&gt;
      process_class_as (l_ast)&lt;br /&gt;
      class_post_actions.call ([l_ast])&lt;br /&gt;
      last_run_successful := True&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code analyzes a class for all active ''standard'' rules. &amp;lt;e&amp;gt;class_pre_actions&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;class_post_actions&amp;lt;/e&amp;gt; are action sequences that are identical to those for the AST nodes. &amp;lt;e&amp;gt;process_class_as&amp;lt;/e&amp;gt;, which is implemented in &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt; will recursively visit all relevant AST nodes and execute their action sequences.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15100</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15100"/>
				<updated>2014-03-07T17:55:55Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* Rule checking */ Checking Standard Rules&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] | [[User:Stefan/Code Analysis/UI Implementation|8. UI Implementation &amp;amp;gt; &amp;amp;gt;]]&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# 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'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
The whole '''code analysis framework''' is located in the '''library ''code_analysis'''''.&lt;br /&gt;
&lt;br /&gt;
== Class Relations ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows an overview of the relations between the classes of the code analysis framework. All classes are located in the ''code_analysis'' library except for &amp;lt;e&amp;gt;CLASS_C&amp;lt;/e&amp;gt; (EiffelStudio), &amp;lt;e&amp;gt;ROTA_TIMED_TASK_I&amp;lt;/e&amp;gt; (''ecosystem'' cluster), &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; (command-line interface), and &amp;lt;e&amp;gt;ES_CODE_ANALYSIS_BENCH_HELPER&amp;lt;/e&amp;gt; (GUI).&lt;br /&gt;
&lt;br /&gt;
[[File:CA Framework Diagram.png|thumb|center|800px|The most interesting classes of the code analysis framework.]]&lt;br /&gt;
&lt;br /&gt;
== Interface ==&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Rule checking ==&lt;br /&gt;
&lt;br /&gt;
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'', &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;. In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt; this task (&amp;lt;e&amp;gt;l_task&amp;lt;/e&amp;gt;) is invoked as follows:&lt;br /&gt;
&lt;br /&gt;
=== In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed)&lt;br /&gt;
l_task.set_output_actions (output_actions)&lt;br /&gt;
rota.run_task (l_task)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; essentially runs the whole analysis. Like all other conformants to &amp;lt;e&amp;gt;{ROTA_TASK_I}&amp;lt;/e&amp;gt; this class executes a series of ''steps'' between which the user interface gets some time to process its events. In &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; each step analyses one class. This means that a class is checked by ''all'' the rules for violations. The following code does that:&lt;br /&gt;
&lt;br /&gt;
=== From &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
step&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
  do&lt;br /&gt;
    if has_next_step then&lt;br /&gt;
        -- Gather type information&lt;br /&gt;
      type_recorder.clear&lt;br /&gt;
      type_recorder.analyze_class (classes.item)&lt;br /&gt;
      context.set_node_types (type_recorder.node_types)&lt;br /&gt;
      context.set_checking_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      across rules as l_rules loop&lt;br /&gt;
          -- If rule is non-standard then it will not be checked by l_rules_checker.&lt;br /&gt;
          -- We will have the rule check the current class here:&lt;br /&gt;
        if&lt;br /&gt;
          l_rules.item.is_enabled.value&lt;br /&gt;
          and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule&lt;br /&gt;
        then&lt;br /&gt;
          l_cfg_rule.check_class (classes.item)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
        -- Status output.&lt;br /&gt;
      if output_actions /= Void then&lt;br /&gt;
        output_actions.call ([ca_messages.analyzing_class (classes.item.name)])&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      rules_checker.run_on_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      classes.forth&lt;br /&gt;
      has_next_step := not classes.after&lt;br /&gt;
      if not has_next_step then&lt;br /&gt;
        completed_action.call ([exceptions])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  rescue&lt;br /&gt;
      -- Instant error output.&lt;br /&gt;
    if output_actions /= Void then&lt;br /&gt;
      output_actions.call ([ca_messages.error_on_class (classes.item.name)])&lt;br /&gt;
    end&lt;br /&gt;
    exceptions.extend ([exception_manager.last_exception, classes.item])&lt;br /&gt;
      -- Jump to the next class.&lt;br /&gt;
    classes.forth&lt;br /&gt;
    has_next_step := not classes.after&lt;br /&gt;
    if not has_next_step then&lt;br /&gt;
      completed_action.call ([exceptions])&lt;br /&gt;
    end&lt;br /&gt;
    retry&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;type_recorder&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_AST_TYPE_RECORDER}&amp;lt;/e&amp;gt;. 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. &amp;lt;e&amp;gt;context&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;e&amp;gt;across&amp;lt;/e&amp;gt; loop only checks ''control flow graph rules''. All the ''standard'' rules are checked by the line &amp;lt;e&amp;gt;rules_checker.run_on_class (classes.item)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;rules_checker&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt;. This is the class where each rule must register the AST nodes the rule visits. &amp;lt;e&amp;gt;run_on_class&amp;lt;/e&amp;gt; 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. &amp;lt;e&amp;gt;step&amp;lt;/e&amp;gt; is executed repeatedly until there are no classes left to analyze.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;e&amp;gt;rescue&amp;lt;/e&amp;gt; clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.&lt;br /&gt;
&lt;br /&gt;
=== Checking ''Standard'' Rules ===&lt;br /&gt;
&lt;br /&gt;
The relatively large class &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; is responsible for checking ''standard rules''. It does this in a straightforward way. It is a subclass of &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt;, a realization of a visitor on the AST.&lt;br /&gt;
&lt;br /&gt;
Rules can register their actions with &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt; by calling a procedure like &amp;lt;e&amp;gt;add_bin_lt_pre_action (a_action: attached PROCEDURE [ANY, TUPLE [BIN_LT_AS]])&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&amp;lt;/e&amp;gt;. These &amp;quot;pre&amp;quot; and &amp;quot;post&amp;quot; actions exist for many other types of AST nodes as well. All the registered actions are stored in &amp;lt;e&amp;gt;ACTION_SEQUENCE&amp;lt;/e&amp;gt; variables:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
if_pre_actions, if_post_actions: ACTION_SEQUENCE [TUPLE [IF_AS]]&lt;br /&gt;
&lt;br /&gt;
add_if_post_action (a_action: attached PROCEDURE [ANY, TUPLE [IF_AS]])&lt;br /&gt;
  do&lt;br /&gt;
    if_post_actions.extend (a_action)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding visitor procedures are redefined. This is done is the following way:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
process_if_as (a_if: IF_AS)&lt;br /&gt;
  do&lt;br /&gt;
    if_pre_actions.call ([a_if])&lt;br /&gt;
    Precursor (a_if)&lt;br /&gt;
    if_post_actions.call ([a_if])&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
-- And similar for all other relevant AST nodes...&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the actual iteration over the AST is done in the ancestor we need only very little code to analyze a class:&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
feature {CA_RULE_CHECKING_TASK} -- Execution Commands&lt;br /&gt;
&lt;br /&gt;
  run_on_class (a_class_to_check: CLASS_C)&lt;br /&gt;
      -- Check all rules that have added their agents.&lt;br /&gt;
    local&lt;br /&gt;
      l_ast: CLASS_AS&lt;br /&gt;
    do&lt;br /&gt;
      last_run_successful := False&lt;br /&gt;
      l_ast := a_class_to_check.ast&lt;br /&gt;
      class_pre_actions.call ([l_ast])&lt;br /&gt;
      process_class_as (l_ast)&lt;br /&gt;
      class_post_actions.call ([l_ast])&lt;br /&gt;
      last_run_successful := True&lt;br /&gt;
    end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code analyzes a class for all active ''standard'' rules. &amp;lt;e&amp;gt;class_pre_actions&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;class_post_actions&amp;lt;/e&amp;gt; are action sequences that are identical to those for the AST nodes. &amp;lt;e&amp;gt;process_class_as&amp;lt;/e&amp;gt;, which is implemented in &amp;lt;e&amp;gt;{AST_ITERATOR}&amp;lt;/e&amp;gt; will recursively visit all relevant AST nodes and execute their action sequences.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:CA_Framework_Diagram.png&amp;diff=15099</id>
		<title>File:CA Framework Diagram.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:CA_Framework_Diagram.png&amp;diff=15099"/>
				<updated>2014-03-07T17:37:28Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: Stefan uploaded a new version of &amp;amp;quot;File:CA Framework Diagram.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15098</id>
		<title>CA UI Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15098"/>
				<updated>2014-03-07T17:28:45Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* Graphical User Interface */ Caching&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Library Implementation|&amp;amp;lt;&amp;amp;lt; 7. Library Implementation]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
The classes of the graphical user interface of the code analyzer are all located in the ''interface'' cluster of ''EVE'', in the subfolder ''graphical &amp;gt; tools &amp;gt; code_analysis''. Here is a short overview of what the single classes do:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL}&amp;lt;/e&amp;gt; : Represents the code analysis GUI tool. Contains the tool title and icon, otherwise not much interesting stuff.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL_PANEL}&amp;lt;/e&amp;gt; : The graphical panel for the code analysis tool. It contains buttons, labels, the rule violations table view, and other user interface elements.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; : 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_BENCH_HELPER}&amp;lt;/e&amp;gt; : A helper class for the integration of the code analysis tool. It contains shared instances of &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;, which are used by the GUI.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_SHOW_PREFERENCES_COMMAND}&amp;lt;/e&amp;gt; : The command is used by the ''Preferences'' button in the panel.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_FIX_EXECUTOR}&amp;lt;/e&amp;gt; : This class [[User:Stefan/Code Analysis/Using Analysis Results#Fixing Rule Violations|fixes]] a rule violation that has been found by the code analysis tool.&lt;br /&gt;
&lt;br /&gt;
These are roughly the class relations for the code analysis GUI:&lt;br /&gt;
[[File:CA GUI Diagram.png|thumb|center|650px|The most interesting class relations of the code analysis GUI.]]&lt;br /&gt;
&lt;br /&gt;
=== Caching ===&lt;br /&gt;
&lt;br /&gt;
It is a common case that GUI users run the code analyzer again after having made some changes to the code. We do not need to analyze the same unchanged code again and again. Therefore code analysis caches the results in memory. This only applies to the GUI mode.&lt;br /&gt;
&lt;br /&gt;
Code analysis uses cached results exactly in one case: when the whole system is analyzed and the previous analysis was on the whole system, too.&lt;br /&gt;
&lt;br /&gt;
The caching functionality is implemented in &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;. When the command for analyzing the system is executed, the timestamps of the last modification of the classes are stored in &amp;lt;e&amp;gt;analysis_timestamp : HASH_TABLE [INTEGER, CLASS_I]&amp;lt;/e&amp;gt; before the analysis. Note that the cached results (the rule violations) themselves are managed by &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt;. The only difference to a non-cached analysis is that the rule violations are not deleted by &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; before the next analysis. Then, in case the next command is also for analyzing the whole system, the current timestamps are compared to the stored timestamps. Any class that has been changed in the meantime will be analyzed again; for any unchanged class the rule violations are taken from the cache.&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;br /&gt;
&lt;br /&gt;
The whole command-line functionality of the code analyzer is located in the class &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. It is located in the ''tty'' cluster of ''EVE''. &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt; is invoked by &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the root class for the ''batch'' (command-line) version of EiffelStudio. In &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the invocation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
elseif option.is_equal (&amp;quot;-code-analysis&amp;quot;) then&lt;br /&gt;
  l_at_args := arguments_in_range (current_option + 1, argument_count)&lt;br /&gt;
  current_option := argument_count + 1&lt;br /&gt;
  create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any command-line arguments after ''-code-analysis'' are passed on to &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. This class, in its creation procedure, processes the arguments as described in [[User:Stefan/Code_Analysis/Command Line Usage|Command Line Usage]]. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure &amp;lt;e&amp;gt;execute&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; of course uses the ''code_analysis'' library and the previously described interface of &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;. After analysis a list of rule violations is output to the command-line. In the code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
across l_code_analyzer.rule_violations as l_vlist loop&lt;br /&gt;
  if not l_vlist.item.is_empty then&lt;br /&gt;
    l_has_violations := True&lt;br /&gt;
      -- Always sort the rule violations by the class they are referring to.&lt;br /&gt;
    output_window.add (ca_messages.cmd_class + l_vlist.key.name + &amp;quot;':%N&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting.&lt;br /&gt;
    across l_vlist.item as ic loop&lt;br /&gt;
      l_rule_name := ic.item.rule.title&lt;br /&gt;
      l_rule_id := ic.item.rule.id&lt;br /&gt;
      if attached ic.item.location as l_loc then&lt;br /&gt;
        l_line := ic.item.location.line.out&lt;br /&gt;
        l_col := ic.item.location.column.out&lt;br /&gt;
        output_window.add (&amp;quot;  (&amp;quot; + l_line + &amp;quot;:&amp;quot; + l_col + &amp;quot;): &amp;quot;&lt;br /&gt;
          + l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      else -- No location attached. Print without location.&lt;br /&gt;
        output_window.add (&amp;quot;  &amp;quot;	+ l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      ic.item.format_violation_description (output_window)&lt;br /&gt;
      output_window.add (&amp;quot;%N&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not l_has_violations then output_window.add (ca_messages.no_issues + &amp;quot;%N&amp;quot;) end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15097</id>
		<title>CA UI Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15097"/>
				<updated>2014-03-07T17:06:06Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* Graphical User Interface */ + class diagram&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Library Implementation|&amp;amp;lt;&amp;amp;lt; 7. Library Implementation]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
The classes of the graphical user interface of the code analyzer are all located in the ''interface'' cluster of ''EVE'', in the subfolder ''graphical &amp;gt; tools &amp;gt; code_analysis''. Here is a short overview of what the single classes do:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL}&amp;lt;/e&amp;gt; : Represents the code analysis GUI tool. Contains the tool title and icon, otherwise not much interesting stuff.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL_PANEL}&amp;lt;/e&amp;gt; : The graphical panel for the code analysis tool. It contains buttons, labels, the rule violations table view, and other user interface elements.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; : 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_BENCH_HELPER}&amp;lt;/e&amp;gt; : A helper class for the integration of the code analysis tool. It contains shared instances of &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;, which are used by the GUI.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_SHOW_PREFERENCES_COMMAND}&amp;lt;/e&amp;gt; : The command is used by the ''Preferences'' button in the panel.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_FIX_EXECUTOR}&amp;lt;/e&amp;gt; : This class [[User:Stefan/Code Analysis/Using Analysis Results#Fixing Rule Violations|fixes]] a rule violation that has been found by the code analysis tool.&lt;br /&gt;
&lt;br /&gt;
These are roughly the class relations for the code analysis GUI:&lt;br /&gt;
[[File:CA GUI Diagram.png|thumb|center|650px|The most interesting class relations of the code analysis GUI.]]&lt;br /&gt;
&lt;br /&gt;
=== Caching ===&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;br /&gt;
&lt;br /&gt;
The whole command-line functionality of the code analyzer is located in the class &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. It is located in the ''tty'' cluster of ''EVE''. &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt; is invoked by &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the root class for the ''batch'' (command-line) version of EiffelStudio. In &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the invocation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
elseif option.is_equal (&amp;quot;-code-analysis&amp;quot;) then&lt;br /&gt;
  l_at_args := arguments_in_range (current_option + 1, argument_count)&lt;br /&gt;
  current_option := argument_count + 1&lt;br /&gt;
  create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any command-line arguments after ''-code-analysis'' are passed on to &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. This class, in its creation procedure, processes the arguments as described in [[User:Stefan/Code_Analysis/Command Line Usage|Command Line Usage]]. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure &amp;lt;e&amp;gt;execute&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; of course uses the ''code_analysis'' library and the previously described interface of &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;. After analysis a list of rule violations is output to the command-line. In the code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
across l_code_analyzer.rule_violations as l_vlist loop&lt;br /&gt;
  if not l_vlist.item.is_empty then&lt;br /&gt;
    l_has_violations := True&lt;br /&gt;
      -- Always sort the rule violations by the class they are referring to.&lt;br /&gt;
    output_window.add (ca_messages.cmd_class + l_vlist.key.name + &amp;quot;':%N&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting.&lt;br /&gt;
    across l_vlist.item as ic loop&lt;br /&gt;
      l_rule_name := ic.item.rule.title&lt;br /&gt;
      l_rule_id := ic.item.rule.id&lt;br /&gt;
      if attached ic.item.location as l_loc then&lt;br /&gt;
        l_line := ic.item.location.line.out&lt;br /&gt;
        l_col := ic.item.location.column.out&lt;br /&gt;
        output_window.add (&amp;quot;  (&amp;quot; + l_line + &amp;quot;:&amp;quot; + l_col + &amp;quot;): &amp;quot;&lt;br /&gt;
          + l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      else -- No location attached. Print without location.&lt;br /&gt;
        output_window.add (&amp;quot;  &amp;quot;	+ l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      ic.item.format_violation_description (output_window)&lt;br /&gt;
      output_window.add (&amp;quot;%N&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not l_has_violations then output_window.add (ca_messages.no_issues + &amp;quot;%N&amp;quot;) end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:CA_GUI_Diagram.png&amp;diff=15096</id>
		<title>File:CA GUI Diagram.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:CA_GUI_Diagram.png&amp;diff=15096"/>
				<updated>2014-03-07T17:02:21Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: Stefan uploaded a new version of &amp;amp;quot;File:CA GUI Diagram.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:CA_GUI_Diagram.png&amp;diff=15095</id>
		<title>File:CA GUI Diagram.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:CA_GUI_Diagram.png&amp;diff=15095"/>
				<updated>2014-03-07T17:00:56Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15094</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15094"/>
				<updated>2014-03-07T12:33:13Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: + class diagram&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] | [[User:Stefan/Code Analysis/UI Implementation|8. UI Implementation &amp;amp;gt; &amp;amp;gt;]]&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# 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'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
The whole '''code analysis framework''' is located in the '''library ''code_analysis'''''.&lt;br /&gt;
&lt;br /&gt;
== Class Relations ==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows an overview of the relations between the classes of the code analysis framework. All classes are located in the ''code_analysis'' library except for &amp;lt;e&amp;gt;CLASS_C&amp;lt;/e&amp;gt; (EiffelStudio), &amp;lt;e&amp;gt;ROTA_TIMED_TASK_I&amp;lt;/e&amp;gt; (''ecosystem'' cluster), &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; (command-line interface), and &amp;lt;e&amp;gt;ES_CODE_ANALYSIS_BENCH_HELPER&amp;lt;/e&amp;gt; (GUI).&lt;br /&gt;
&lt;br /&gt;
[[File:CA Framework Diagram.png|thumb|center|800px|The most interesting classes of the code analysis framework.]]&lt;br /&gt;
&lt;br /&gt;
== Interface ==&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Rule checking ==&lt;br /&gt;
&lt;br /&gt;
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'', &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;. In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt; this task (&amp;lt;e&amp;gt;l_task&amp;lt;/e&amp;gt;) is invoked as follows:&lt;br /&gt;
&lt;br /&gt;
=== In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed)&lt;br /&gt;
l_task.set_output_actions (output_actions)&lt;br /&gt;
rota.run_task (l_task)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; essentially runs the whole analysis. Like all other conformants to &amp;lt;e&amp;gt;{ROTA_TASK_I}&amp;lt;/e&amp;gt; this class executes a series of ''steps'' between which the user interface gets some time to process its events. In &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; each step analyses one class. This means that a class is checked by ''all'' the rules for violations. The following code does that:&lt;br /&gt;
&lt;br /&gt;
=== From &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
step&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
  do&lt;br /&gt;
    if has_next_step then&lt;br /&gt;
        -- Gather type information&lt;br /&gt;
      type_recorder.clear&lt;br /&gt;
      type_recorder.analyze_class (classes.item)&lt;br /&gt;
      context.set_node_types (type_recorder.node_types)&lt;br /&gt;
      context.set_checking_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      across rules as l_rules loop&lt;br /&gt;
          -- If rule is non-standard then it will not be checked by l_rules_checker.&lt;br /&gt;
          -- We will have the rule check the current class here:&lt;br /&gt;
        if&lt;br /&gt;
          l_rules.item.is_enabled.value&lt;br /&gt;
          and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule&lt;br /&gt;
        then&lt;br /&gt;
          l_cfg_rule.check_class (classes.item)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
        -- Status output.&lt;br /&gt;
      if output_actions /= Void then&lt;br /&gt;
        output_actions.call ([ca_messages.analyzing_class (classes.item.name)])&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      rules_checker.run_on_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      classes.forth&lt;br /&gt;
      has_next_step := not classes.after&lt;br /&gt;
      if not has_next_step then&lt;br /&gt;
        completed_action.call ([exceptions])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  rescue&lt;br /&gt;
      -- Instant error output.&lt;br /&gt;
    if output_actions /= Void then&lt;br /&gt;
      output_actions.call ([ca_messages.error_on_class (classes.item.name)])&lt;br /&gt;
    end&lt;br /&gt;
    exceptions.extend ([exception_manager.last_exception, classes.item])&lt;br /&gt;
      -- Jump to the next class.&lt;br /&gt;
    classes.forth&lt;br /&gt;
    has_next_step := not classes.after&lt;br /&gt;
    if not has_next_step then&lt;br /&gt;
      completed_action.call ([exceptions])&lt;br /&gt;
    end&lt;br /&gt;
    retry&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;type_recorder&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_AST_TYPE_RECORDER}&amp;lt;/e&amp;gt;. 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. &amp;lt;e&amp;gt;context&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;e&amp;gt;across&amp;lt;/e&amp;gt; loop only checks ''control flow graph rules''. All the ''standard'' rules are checked by the line &amp;lt;e&amp;gt;rules_checker.run_on_class (classes.item)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;rules_checker&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt;. This is the class where each rule must register the AST nodes the rule visits. &amp;lt;e&amp;gt;run_on_class&amp;lt;/e&amp;gt; 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. &amp;lt;e&amp;gt;step&amp;lt;/e&amp;gt; is executed repeatedly until there are no classes left to analyze.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;e&amp;gt;rescue&amp;lt;/e&amp;gt; clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:CA_Framework_Diagram.png&amp;diff=15093</id>
		<title>File:CA Framework Diagram.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:CA_Framework_Diagram.png&amp;diff=15093"/>
				<updated>2014-03-07T12:24:21Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: Stefan uploaded a new version of &amp;amp;quot;File:CA Framework Diagram.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:CA_Framework_Diagram.png&amp;diff=15092</id>
		<title>File:CA Framework Diagram.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:CA_Framework_Diagram.png&amp;diff=15092"/>
				<updated>2014-03-07T12:23:06Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15091</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15091"/>
				<updated>2014-03-07T11:13:17Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: removed section on UI&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] | [[User:Stefan/Code Analysis/UI Implementation|8. UI Implementation &amp;amp;gt; &amp;amp;gt;]]&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# 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'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
The whole '''code analysis framework''' is located in the '''library ''code_analysis'''''.&lt;br /&gt;
&lt;br /&gt;
== Interface ==&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Rule checking ==&lt;br /&gt;
&lt;br /&gt;
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'', &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;. In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt; this task (&amp;lt;e&amp;gt;l_task&amp;lt;/e&amp;gt;) is invoked as follows:&lt;br /&gt;
&lt;br /&gt;
=== In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed)&lt;br /&gt;
l_task.set_output_actions (output_actions)&lt;br /&gt;
rota.run_task (l_task)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; essentially runs the whole analysis. Like all other conformants to &amp;lt;e&amp;gt;{ROTA_TASK_I}&amp;lt;/e&amp;gt; this class executes a series of ''steps'' between which the user interface gets some time to process its events. In &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; each step analyses one class. This means that a class is checked by ''all'' the rules for violations. The following code does that:&lt;br /&gt;
&lt;br /&gt;
=== From &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;: ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
step&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
  do&lt;br /&gt;
    if has_next_step then&lt;br /&gt;
        -- Gather type information&lt;br /&gt;
      type_recorder.clear&lt;br /&gt;
      type_recorder.analyze_class (classes.item)&lt;br /&gt;
      context.set_node_types (type_recorder.node_types)&lt;br /&gt;
      context.set_checking_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      across rules as l_rules loop&lt;br /&gt;
          -- If rule is non-standard then it will not be checked by l_rules_checker.&lt;br /&gt;
          -- We will have the rule check the current class here:&lt;br /&gt;
        if&lt;br /&gt;
          l_rules.item.is_enabled.value&lt;br /&gt;
          and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule&lt;br /&gt;
        then&lt;br /&gt;
          l_cfg_rule.check_class (classes.item)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
        -- Status output.&lt;br /&gt;
      if output_actions /= Void then&lt;br /&gt;
        output_actions.call ([ca_messages.analyzing_class (classes.item.name)])&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      rules_checker.run_on_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      classes.forth&lt;br /&gt;
      has_next_step := not classes.after&lt;br /&gt;
      if not has_next_step then&lt;br /&gt;
        completed_action.call ([exceptions])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  rescue&lt;br /&gt;
      -- Instant error output.&lt;br /&gt;
    if output_actions /= Void then&lt;br /&gt;
      output_actions.call ([ca_messages.error_on_class (classes.item.name)])&lt;br /&gt;
    end&lt;br /&gt;
    exceptions.extend ([exception_manager.last_exception, classes.item])&lt;br /&gt;
      -- Jump to the next class.&lt;br /&gt;
    classes.forth&lt;br /&gt;
    has_next_step := not classes.after&lt;br /&gt;
    if not has_next_step then&lt;br /&gt;
      completed_action.call ([exceptions])&lt;br /&gt;
    end&lt;br /&gt;
    retry&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;type_recorder&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_AST_TYPE_RECORDER}&amp;lt;/e&amp;gt;. 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. &amp;lt;e&amp;gt;context&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;e&amp;gt;across&amp;lt;/e&amp;gt; loop only checks ''control flow graph rules''. All the ''standard'' rules are checked by the line &amp;lt;e&amp;gt;rules_checker.run_on_class (classes.item)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;rules_checker&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt;. This is the class where each rule must register the AST nodes the rule visits. &amp;lt;e&amp;gt;run_on_class&amp;lt;/e&amp;gt; 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. &amp;lt;e&amp;gt;step&amp;lt;/e&amp;gt; is executed repeatedly until there are no classes left to analyze.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;e&amp;gt;rescue&amp;lt;/e&amp;gt; clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15090</id>
		<title>CA UI Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_UI_Implementation&amp;diff=15090"/>
				<updated>2014-03-07T11:09:22Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: initial version - moved from former chapter 7&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Library Implementation|&amp;amp;lt;&amp;amp;lt; 7. Library Implementation]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
The classes of the graphical user interface of the code analyzer are all located in the ''interface'' cluster of ''EVE'', in the subfolder ''graphical &amp;gt; tools &amp;gt; code_analysis''. Here is a short overview of what the single classes do:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL}&amp;lt;/e&amp;gt; : Represents the code analysis GUI tool. Contains the tool title and icon, otherwise not much interesting stuff.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL_PANEL}&amp;lt;/e&amp;gt; : The graphical panel for the code analysis tool. It contains buttons, labels, the rule violations table view, and other user interface elements.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; : 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_BENCH_HELPER}&amp;lt;/e&amp;gt; : A helper class for the integration of the code analysis tool. It contains shared instances of &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;, which are used by the GUI.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_SHOW_PREFERENCES_COMMAND}&amp;lt;/e&amp;gt; : The command is used by the ''Preferences'' button in the panel.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_FIX_EXECUTOR}&amp;lt;/e&amp;gt; : This class [[User:Stefan/Code Analysis/Using Analysis Results#Fixing Rule Violations|fixes]] a rule violation that has been found by the code analysis tool.&lt;br /&gt;
&lt;br /&gt;
=== Caching ===&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;br /&gt;
&lt;br /&gt;
The whole command-line functionality of the code analyzer is located in the class &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. It is located in the ''tty'' cluster of ''EVE''. &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt; is invoked by &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the root class for the ''batch'' (command-line) version of EiffelStudio. In &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the invocation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
elseif option.is_equal (&amp;quot;-code-analysis&amp;quot;) then&lt;br /&gt;
  l_at_args := arguments_in_range (current_option + 1, argument_count)&lt;br /&gt;
  current_option := argument_count + 1&lt;br /&gt;
  create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any command-line arguments after ''-code-analysis'' are passed on to &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. This class, in its creation procedure, processes the arguments as described in [[User:Stefan/Code_Analysis/Command Line Usage|Command Line Usage]]. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure &amp;lt;e&amp;gt;execute&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; of course uses the ''code_analysis'' library and the previously described interface of &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;. After analysis a list of rule violations is output to the command-line. In the code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
across l_code_analyzer.rule_violations as l_vlist loop&lt;br /&gt;
  if not l_vlist.item.is_empty then&lt;br /&gt;
    l_has_violations := True&lt;br /&gt;
      -- Always sort the rule violations by the class they are referring to.&lt;br /&gt;
    output_window.add (ca_messages.cmd_class + l_vlist.key.name + &amp;quot;':%N&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting.&lt;br /&gt;
    across l_vlist.item as ic loop&lt;br /&gt;
      l_rule_name := ic.item.rule.title&lt;br /&gt;
      l_rule_id := ic.item.rule.id&lt;br /&gt;
      if attached ic.item.location as l_loc then&lt;br /&gt;
        l_line := ic.item.location.line.out&lt;br /&gt;
        l_col := ic.item.location.column.out&lt;br /&gt;
        output_window.add (&amp;quot;  (&amp;quot; + l_line + &amp;quot;:&amp;quot; + l_col + &amp;quot;): &amp;quot;&lt;br /&gt;
          + l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      else -- No location attached. Print without location.&lt;br /&gt;
        output_window.add (&amp;quot;  &amp;quot;	+ l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      ic.item.format_violation_description (output_window)&lt;br /&gt;
      output_window.add (&amp;quot;%N&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not l_has_violations then output_window.add (ca_messages.no_issues + &amp;quot;%N&amp;quot;) end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15089</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15089"/>
				<updated>2014-03-07T11:07:06Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] | [[User:Stefan/Code Analysis/UI Implementation|8. UI Implementation &amp;amp;gt; &amp;amp;gt;]]&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# 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'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
== ''code_analysis'' library ==&lt;br /&gt;
&lt;br /&gt;
The whole code analysis framework is located in the library ''code_analysis''.&lt;br /&gt;
&lt;br /&gt;
=== Interface ===&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Rule checking ===&lt;br /&gt;
&lt;br /&gt;
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'', &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;. In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt; this task (&amp;lt;e&amp;gt;l_task&amp;lt;/e&amp;gt;) is invoked as follows:&lt;br /&gt;
&lt;br /&gt;
==== In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;: ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed)&lt;br /&gt;
l_task.set_output_actions (output_actions)&lt;br /&gt;
rota.run_task (l_task)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; essentially runs the whole analysis. Like all other conformants to &amp;lt;e&amp;gt;{ROTA_TASK_I}&amp;lt;/e&amp;gt; this class executes a series of ''steps'' between which the user interface gets some time to process its events. In &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; each step analyses one class. This means that a class is checked by ''all'' the rules for violations. The following code does that:&lt;br /&gt;
&lt;br /&gt;
==== From &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;: ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
step&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
  do&lt;br /&gt;
    if has_next_step then&lt;br /&gt;
        -- Gather type information&lt;br /&gt;
      type_recorder.clear&lt;br /&gt;
      type_recorder.analyze_class (classes.item)&lt;br /&gt;
      context.set_node_types (type_recorder.node_types)&lt;br /&gt;
      context.set_checking_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      across rules as l_rules loop&lt;br /&gt;
          -- If rule is non-standard then it will not be checked by l_rules_checker.&lt;br /&gt;
          -- We will have the rule check the current class here:&lt;br /&gt;
        if&lt;br /&gt;
          l_rules.item.is_enabled.value&lt;br /&gt;
          and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule&lt;br /&gt;
        then&lt;br /&gt;
          l_cfg_rule.check_class (classes.item)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
        -- Status output.&lt;br /&gt;
      if output_actions /= Void then&lt;br /&gt;
        output_actions.call ([ca_messages.analyzing_class (classes.item.name)])&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      rules_checker.run_on_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      classes.forth&lt;br /&gt;
      has_next_step := not classes.after&lt;br /&gt;
      if not has_next_step then&lt;br /&gt;
        completed_action.call ([exceptions])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  rescue&lt;br /&gt;
      -- Instant error output.&lt;br /&gt;
    if output_actions /= Void then&lt;br /&gt;
      output_actions.call ([ca_messages.error_on_class (classes.item.name)])&lt;br /&gt;
    end&lt;br /&gt;
    exceptions.extend ([exception_manager.last_exception, classes.item])&lt;br /&gt;
      -- Jump to the next class.&lt;br /&gt;
    classes.forth&lt;br /&gt;
    has_next_step := not classes.after&lt;br /&gt;
    if not has_next_step then&lt;br /&gt;
      completed_action.call ([exceptions])&lt;br /&gt;
    end&lt;br /&gt;
    retry&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;type_recorder&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_AST_TYPE_RECORDER}&amp;lt;/e&amp;gt;. 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. &amp;lt;e&amp;gt;context&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;e&amp;gt;across&amp;lt;/e&amp;gt; loop only checks ''control flow graph rules''. All the ''standard'' rules are checked by the line &amp;lt;e&amp;gt;rules_checker.run_on_class (classes.item)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;rules_checker&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt;. This is the class where each rule must register the AST nodes the rule visits. &amp;lt;e&amp;gt;run_on_class&amp;lt;/e&amp;gt; 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. &amp;lt;e&amp;gt;step&amp;lt;/e&amp;gt; is executed repeatedly until there are no classes left to analyze.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;e&amp;gt;rescue&amp;lt;/e&amp;gt; clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
The classes of the graphical user interface of the code analyzer are all located in the ''interface'' cluster of ''EVE'', in the subfolder ''graphical &amp;gt; tools &amp;gt; code_analysis''. Here is a short overview of what the single classes do:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL}&amp;lt;/e&amp;gt; : Represents the code analysis GUI tool. Contains the tool title and icon, otherwise not much interesting stuff.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL_PANEL}&amp;lt;/e&amp;gt; : The graphical panel for the code analysis tool. It contains buttons, labels, the rule violations table view, and other user interface elements.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; : 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_BENCH_HELPER}&amp;lt;/e&amp;gt; : A helper class for the integration of the code analysis tool. It contains shared instances of &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;, which are used by the GUI.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_SHOW_PREFERENCES_COMMAND}&amp;lt;/e&amp;gt; : The command is used by the ''Preferences'' button in the panel.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_FIX_EXECUTOR}&amp;lt;/e&amp;gt; : This class [[User:Stefan/Code Analysis/Using Analysis Results#Fixing Rule Violations|fixes]] a rule violation that has been found by the code analysis tool.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Caching ===&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;br /&gt;
&lt;br /&gt;
The whole command-line functionality of the code analyzer is located in the class &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. It is located in the ''tty'' cluster of ''EVE''. &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt; is invoked by &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the root class for the ''batch'' (command-line) version of EiffelStudio. In &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the invocation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
elseif option.is_equal (&amp;quot;-code-analysis&amp;quot;) then&lt;br /&gt;
  l_at_args := arguments_in_range (current_option + 1, argument_count)&lt;br /&gt;
  current_option := argument_count + 1&lt;br /&gt;
  create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any command-line arguments after ''-code-analysis'' are passed on to &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. This class, in its creation procedure, processes the arguments as described in [[User:Stefan/Code_Analysis/Command Line Usage|Command Line Usage]]. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure &amp;lt;e&amp;gt;execute&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; of course uses the ''code_analysis'' library and the previously described interface of &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;. After analysis a list of rule violations is output to the command-line. In the code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
across l_code_analyzer.rule_violations as l_vlist loop&lt;br /&gt;
  if not l_vlist.item.is_empty then&lt;br /&gt;
    l_has_violations := True&lt;br /&gt;
      -- Always sort the rule violations by the class they are referring to.&lt;br /&gt;
    output_window.add (ca_messages.cmd_class + l_vlist.key.name + &amp;quot;':%N&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting.&lt;br /&gt;
    across l_vlist.item as ic loop&lt;br /&gt;
      l_rule_name := ic.item.rule.title&lt;br /&gt;
      l_rule_id := ic.item.rule.id&lt;br /&gt;
      if attached ic.item.location as l_loc then&lt;br /&gt;
        l_line := ic.item.location.line.out&lt;br /&gt;
        l_col := ic.item.location.column.out&lt;br /&gt;
        output_window.add (&amp;quot;  (&amp;quot; + l_line + &amp;quot;:&amp;quot; + l_col + &amp;quot;): &amp;quot;&lt;br /&gt;
          + l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      else -- No location attached. Print without location.&lt;br /&gt;
        output_window.add (&amp;quot;  &amp;quot;	+ l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      ic.item.format_violation_description (output_window)&lt;br /&gt;
      output_window.add (&amp;quot;%N&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not l_has_violations then output_window.add (ca_messages.no_issues + &amp;quot;%N&amp;quot;) end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15088</id>
		<title>CA Adding New Rules</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15088"/>
				<updated>2014-03-07T11:05:37Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Command Line Usage|&amp;amp;lt;&amp;amp;lt; 5. Command Line Usage]] | [[User:Stefan/Code Analysis/Library Implementation|7. Library Implementation &amp;amp;gt;&amp;amp;gt;]] &amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
The Code Analysis framework was designed with regard to the fact that '''adding new rules''' should be as simple and as fast as possible. Looking at the initial set of rules that were implemented, nearly all of them have an implementation of less than 200 lines of code. Many of them use even less than 100 lines of code. Rules that search the code for certain patterns (this applies to the vast majority of rules) are particularly simple to implement.&lt;br /&gt;
&lt;br /&gt;
This page shows you how to implement a rule in the form of a class. After you have written such a class you must add the rule to the list of rules. This list is populated in &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.make&amp;lt;/e&amp;gt;. There, just below the lines where all the other rules are added add a line like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;rules.extend (create {YOUR_RULE}.make)&amp;lt;/e&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;e&amp;gt;YOUR_RULE&amp;lt;/e&amp;gt; must be replaced by the name of your rule class and the creation procedure (&amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt;) must be adapted if necessary.&lt;br /&gt;
&lt;br /&gt;
== Standard Rules ==&lt;br /&gt;
&lt;br /&gt;
All rules must conform to &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. The class you implement for a rule is on one hand responsible for checking the rule and contains metadata about the rule (i. e. title, description) on the other hand. As of now, rules must moreover conform to either &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;CA_CFG_RULE&amp;lt;/e&amp;gt;, both of which are subtypes of &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. A large number of possible rules are ''standard rules'', no matter whether they are trivial or more complicated.&lt;br /&gt;
&lt;br /&gt;
All ''Standard rules'' are checked by iterating over the [http://en.wikipedia.org/wiki/Abstract_syntax_tree abstract syntax tree] (AST) of the class code. The developer who adds a new rule can very well ignore the details thereof. He needs to know however which AST nodes his rule needs to process. For each type of AST node you need to add an agent so your routine will be called during the iteration on the AST.&lt;br /&gt;
&lt;br /&gt;
To start implementing your rule you have basically two possibilities. (1) You start from scratch, implementing all deferred features of &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or (2) you use the following template.&lt;br /&gt;
&lt;br /&gt;
=== Standard Rule Template ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
class&lt;br /&gt;
  CA_YOUR_RULE&lt;br /&gt;
&lt;br /&gt;
inherit&lt;br /&gt;
  CA_STANDARD_RULE&lt;br /&gt;
&lt;br /&gt;
create&lt;br /&gt;
  make&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Initialization&lt;br /&gt;
&lt;br /&gt;
  make (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initialization for `Current'.&lt;br /&gt;
    do&lt;br /&gt;
      make_with_defaults&lt;br /&gt;
        -- This initializes the attributes to their default values:&lt;br /&gt;
        -- Severity = warning&lt;br /&gt;
        -- Default Severity Score = 50 (`severity score' can be changed by user)&lt;br /&gt;
        -- Rule enabled by default = True (`Rule enabled' can be changed by user)&lt;br /&gt;
        -- Only for system wide checks = False&lt;br /&gt;
        -- Checks library classes = True&lt;br /&gt;
        -- Checks nonlibrary classes = True&lt;br /&gt;
&lt;br /&gt;
        initialize_options (a_pref_manager)&lt;br /&gt;
&lt;br /&gt;
        -- TODO: Add your initialization here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  initialize_options (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initializes the rule preferences.&lt;br /&gt;
    local&lt;br /&gt;
      l_factory: BASIC_PREFERENCE_FACTORY&lt;br /&gt;
    do&lt;br /&gt;
      create l_factory&lt;br /&gt;
     &lt;br /&gt;
        -- TODO: Add the initialization of your custom preferences here.&lt;br /&gt;
        -- Example:&lt;br /&gt;
--    threshold := l_factory.new_integer_preference_value (a_pref_manager,&lt;br /&gt;
--      preference_namespace + &amp;quot;Threshold&amp;quot;,&lt;br /&gt;
--      30)  -- default value&lt;br /&gt;
--    min_local_name_length.set_default_value (&amp;quot;30&amp;quot;) -- default value, too&lt;br /&gt;
--    min_local_name_length.set_validation_agent (agent is_integer_string_within_bounds (?, 1, 1_000_000))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add agents for the features in section `Rule checking' here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Rule checking&lt;br /&gt;
&lt;br /&gt;
  -- TODO: Add the AST processing here.&lt;br /&gt;
&lt;br /&gt;
feature -- Properties&lt;br /&gt;
&lt;br /&gt;
  title: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the title of your rule here.&lt;br /&gt;
      Result := &amp;quot;(Your title)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- TODO: Add the ID of your rule here. Should be unique!&lt;br /&gt;
  id: STRING_32 = &amp;quot;(YourID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  description: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the rule description here.&lt;br /&gt;
      Result :=  &amp;quot;(Your description)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add a formatted description of a concrete violation of this rule here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let us have a closer look at the various parts of a rule class.&lt;br /&gt;
&lt;br /&gt;
=== Initialization ===&lt;br /&gt;
&lt;br /&gt;
Calling &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt; initializes the attributes to their default values and makes sure that the class invariant is true. If you want to set an attribute to a custom value you can do so by setting it after the call to &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The creation procedure from the template takes an argument of type &amp;lt;e&amp;gt;PREFERENCE_MANAGER&amp;lt;/e&amp;gt;. This is used for initializing preferences that are specific to your rule. Such preferences usually represent integral or boolean values. If you do ''not'' need any custom preferences then you can leave out the argument &amp;lt;e&amp;gt;a_pref_manager&amp;lt;/e&amp;gt; of &amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt; and you can remove the whole &amp;lt;e&amp;gt;initialize_options&amp;lt;/e&amp;gt; feature.&lt;br /&gt;
&lt;br /&gt;
=== AST processing ===&lt;br /&gt;
&lt;br /&gt;
The main part of your rule implementation consists of checking the source code for rule violations. Say, for example, that you want to check &amp;lt;e&amp;gt;if&amp;lt;/e&amp;gt; instructions to have certain properties. Then you would add a feature like &amp;lt;e&amp;gt;process_if (a_if_ast: IF_AS)&amp;lt;/e&amp;gt; to the section ''Rule checking''. Also, you would need to modify the &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt; feature by adding the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;a_checker.add_if_pre_action (agent process_if)&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Of course you may register as many such agents as you want.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
The ''title'' and the ''description'' of the rule may be constant strings, they may also be localized strings. The ''rule ID'' must be unique among all rules. It should not contain spaces and should be reasonably short. The main rules that come with ''Code Analysis'' have IDs that are numbered from CA001 to CA999 (many of which are not used).&lt;br /&gt;
&lt;br /&gt;
=== Formatted Violation Description ===&lt;br /&gt;
&lt;br /&gt;
Your rule should be able to produce a formatted description of a concrete rule violation. This description is for example used in the Code Analysis tool panel of the GUI. There, class names and feature names are enabled for pick-and-drop. Variable names, numbers, and strings will be displayed in a nice way, too. In addition, this description is used in command line mode. In order to produce normal, unformatted text, use &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add&amp;lt;/e&amp;gt;. For adding formatted elements use features like &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_local&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_feature_name&amp;lt;/e&amp;gt; and similar.&lt;br /&gt;
&lt;br /&gt;
You should store all the data you need for this description (variables names, numbers, etc.) in &amp;lt;e&amp;gt;{CA_RULE_VIOLATION}.long_description_info&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;format_violation_description&amp;lt;/e&amp;gt; can then retrieve this data for the formatted output. Here is a simple example of producing a formatted description:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
a_formatter.add (&amp;quot;Feature &amp;quot;)&lt;br /&gt;
if attached {STRING_32} a_violation.long_description_info.first as l_feat_name then&lt;br /&gt;
  a_formatter.add_feature_name (l_feat_name, a_violation.affected_class)&lt;br /&gt;
end&lt;br /&gt;
a_formatter.add (&amp;quot; is very long.&amp;quot;)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== More Customized Rules ==&lt;br /&gt;
&lt;br /&gt;
For rules that do not fit into a simple AST visitor scheme you best inherit your rule from &amp;lt;e&amp;gt;{CA_STANDARD_RULE}&amp;lt;/e&amp;gt;, too. You can for example register agents that get called when a ''class'' or a ''feature'' is processed. Based on these agents you can perform your customized analysis on the classes and/or features. Using ''multiple inheritance'' or just aggregation it should hardly be a problem to include any functionality you need for your analysis.&lt;br /&gt;
&lt;br /&gt;
== Accessing Type Information ==&lt;br /&gt;
&lt;br /&gt;
The AST classes do not contain ''type information''. Suppose your rule processes function calls. Feature calls in the AST do not contain any information on the types, such as the type of the result.&lt;br /&gt;
&lt;br /&gt;
The code analysis framework however provides functionality to retrieve the type of AST nodes. Before the analyzer lets a class be analyzed by all the rules it computes the types of the AST nodes of a class. Hence this data will be available to your rule afterwards.&lt;br /&gt;
&lt;br /&gt;
While your rule is being checked you can retrieve the type of node &amp;lt;e&amp;gt;a_node&amp;lt;/e&amp;gt; from feature &amp;lt;e&amp;gt;a_feature&amp;lt;/e&amp;gt; by calling &amp;lt;e&amp;gt;current_context.node_type (a_node: AST_EIFFEL; a_feature: FEATURE_I)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;{CA_RULE}.current_context&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; and contains other information about current rule checking, too, such as the currently processed class or the matchlist for this class.&lt;br /&gt;
&lt;br /&gt;
== Accessing the Control Flow Graph ==&lt;br /&gt;
&lt;br /&gt;
Some kinds of static code analysis need and use the ''control flow graph'' of a program. The code analysis framework supports rules that use the control flow graph. If there is at least one such rule, the code analyzer computes the control flow graph of the procedures of the analyzed class before letting the ''rule'' check this class.&lt;br /&gt;
&lt;br /&gt;
=== Worklist algorithms ===&lt;br /&gt;
&lt;br /&gt;
''Control flow graph rules'' iterate over the control flow graph. They do it using a ''worklist''—a list of CFG edges that still have to be processed. At the beginning, the worklist contains all edges of the control flow graph. The algorithm will pick edges from the worklist for processing in an arbitrary order. The iteration stops as soon as there are no more edges left in the worklist. How will the worklist get smaller? Each edge that is processed is removed from the worklist. After processing you will have to decide dynamically whether to add all the outgoing (or incoming, depending on the direction) edges to the worklist. Like this you can take the fact into account that some analyses need certain edges to be processed more than once (a fixed point iteration is such an example).&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
A control flow analysis may iterate in either direction. For a forward-directed analysis inherit your rule from &amp;lt;e&amp;gt;{CA_CFG_FORWARD_RULE}&amp;lt;/e&amp;gt;, for a backward analysis use &amp;lt;e&amp;gt;{CA_CFG_BACKWARD_RULE}&amp;lt;/e&amp;gt; instead. In either case you will then have to implement the following deferred features:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;initialize_processing (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; : This is called before a routine is processed using the worklist. Essentially you may use it to initialize and prepare all the data structures you will need during analysis.&lt;br /&gt;
; &amp;lt;e&amp;gt;visit_edge (a_from, a_to: attached CA_CFG_BASIC_BLOCK): BOOLEAN&amp;lt;/e&amp;gt; : This will be called when an edge is being visited. Here, you can put the analysis. If you let &amp;lt;e&amp;gt;Result = False&amp;lt;/e&amp;gt; then no further edges will be added to the worklist. If in contrary you let &amp;lt;e&amp;gt;Result = True&amp;lt;/e&amp;gt; then edges will be added to the worklist: In a ''forward'' analysis all the ''outgoing'' edges of the current one will be added; in a ''backward'' analysis all the ''incoming'' edges will be added.&lt;br /&gt;
&lt;br /&gt;
=== Non-worklist algorithms ===&lt;br /&gt;
&lt;br /&gt;
If your control flow graph does not fit into the structure of an algorithm as described above you may directly inherit from &amp;lt;e&amp;gt;{CA_CFG_RULE}&amp;lt;/e&amp;gt; and implement the feature &amp;lt;e&amp;gt;process_cfg (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; (in addition to the features explained above). In this case you do not have to use a worklist; basically you can process the control flow graph in any way you want.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=User:Stefan/Code_Analysis/Architectural_Overview&amp;diff=15086</id>
		<title>User:Stefan/Code Analysis/Architectural Overview</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=User:Stefan/Code_Analysis/Architectural_Overview&amp;diff=15086"/>
				<updated>2014-03-07T11:03:59Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: Stefan moved page User:Stefan/Code Analysis/Architectural Overview to User:Stefan/Code Analysis/Library Implementation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[User:Stefan/Code Analysis/Library Implementation]]&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15085</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15085"/>
				<updated>2014-03-07T11:03:58Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: Stefan moved page User:Stefan/Code Analysis/Architectural Overview to User:Stefan/Code Analysis/Library Implementation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# 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'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
== ''code_analysis'' library ==&lt;br /&gt;
&lt;br /&gt;
The whole code analysis framework is located in the library ''code_analysis''.&lt;br /&gt;
&lt;br /&gt;
=== Interface ===&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Rule checking ===&lt;br /&gt;
&lt;br /&gt;
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'', &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;. In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt; this task (&amp;lt;e&amp;gt;l_task&amp;lt;/e&amp;gt;) is invoked as follows:&lt;br /&gt;
&lt;br /&gt;
==== In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;: ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed)&lt;br /&gt;
l_task.set_output_actions (output_actions)&lt;br /&gt;
rota.run_task (l_task)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; essentially runs the whole analysis. Like all other conformants to &amp;lt;e&amp;gt;{ROTA_TASK_I}&amp;lt;/e&amp;gt; this class executes a series of ''steps'' between which the user interface gets some time to process its events. In &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; each step analyses one class. This means that a class is checked by ''all'' the rules for violations. The following code does that:&lt;br /&gt;
&lt;br /&gt;
==== From &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;: ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
step&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
  do&lt;br /&gt;
    if has_next_step then&lt;br /&gt;
        -- Gather type information&lt;br /&gt;
      type_recorder.clear&lt;br /&gt;
      type_recorder.analyze_class (classes.item)&lt;br /&gt;
      context.set_node_types (type_recorder.node_types)&lt;br /&gt;
      context.set_checking_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      across rules as l_rules loop&lt;br /&gt;
          -- If rule is non-standard then it will not be checked by l_rules_checker.&lt;br /&gt;
          -- We will have the rule check the current class here:&lt;br /&gt;
        if&lt;br /&gt;
          l_rules.item.is_enabled.value&lt;br /&gt;
          and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule&lt;br /&gt;
        then&lt;br /&gt;
          l_cfg_rule.check_class (classes.item)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
        -- Status output.&lt;br /&gt;
      if output_actions /= Void then&lt;br /&gt;
        output_actions.call ([ca_messages.analyzing_class (classes.item.name)])&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      rules_checker.run_on_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      classes.forth&lt;br /&gt;
      has_next_step := not classes.after&lt;br /&gt;
      if not has_next_step then&lt;br /&gt;
        completed_action.call ([exceptions])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  rescue&lt;br /&gt;
      -- Instant error output.&lt;br /&gt;
    if output_actions /= Void then&lt;br /&gt;
      output_actions.call ([ca_messages.error_on_class (classes.item.name)])&lt;br /&gt;
    end&lt;br /&gt;
    exceptions.extend ([exception_manager.last_exception, classes.item])&lt;br /&gt;
      -- Jump to the next class.&lt;br /&gt;
    classes.forth&lt;br /&gt;
    has_next_step := not classes.after&lt;br /&gt;
    if not has_next_step then&lt;br /&gt;
      completed_action.call ([exceptions])&lt;br /&gt;
    end&lt;br /&gt;
    retry&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;type_recorder&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_AST_TYPE_RECORDER}&amp;lt;/e&amp;gt;. 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. &amp;lt;e&amp;gt;context&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;e&amp;gt;across&amp;lt;/e&amp;gt; loop only checks ''control flow graph rules''. All the ''standard'' rules are checked by the line &amp;lt;e&amp;gt;rules_checker.run_on_class (classes.item)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;rules_checker&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt;. This is the class where each rule must register the AST nodes the rule visits. &amp;lt;e&amp;gt;run_on_class&amp;lt;/e&amp;gt; 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. &amp;lt;e&amp;gt;step&amp;lt;/e&amp;gt; is executed repeatedly until there are no classes left to analyze.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;e&amp;gt;rescue&amp;lt;/e&amp;gt; clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
The classes of the graphical user interface of the code analyzer are all located in the ''interface'' cluster of ''EVE'', in the subfolder ''graphical &amp;gt; tools &amp;gt; code_analysis''. Here is a short overview of what the single classes do:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL}&amp;lt;/e&amp;gt; : Represents the code analysis GUI tool. Contains the tool title and icon, otherwise not much interesting stuff.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL_PANEL}&amp;lt;/e&amp;gt; : The graphical panel for the code analysis tool. It contains buttons, labels, the rule violations table view, and other user interface elements.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; : 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_BENCH_HELPER}&amp;lt;/e&amp;gt; : A helper class for the integration of the code analysis tool. It contains shared instances of &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;, which are used by the GUI.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_SHOW_PREFERENCES_COMMAND}&amp;lt;/e&amp;gt; : The command is used by the ''Preferences'' button in the panel.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_FIX_EXECUTOR}&amp;lt;/e&amp;gt; : This class [[User:Stefan/Code Analysis/Using Analysis Results#Fixing Rule Violations|fixes]] a rule violation that has been found by the code analysis tool.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Caching ===&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;br /&gt;
&lt;br /&gt;
The whole command-line functionality of the code analyzer is located in the class &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. It is located in the ''tty'' cluster of ''EVE''. &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt; is invoked by &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the root class for the ''batch'' (command-line) version of EiffelStudio. In &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the invocation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
elseif option.is_equal (&amp;quot;-code-analysis&amp;quot;) then&lt;br /&gt;
  l_at_args := arguments_in_range (current_option + 1, argument_count)&lt;br /&gt;
  current_option := argument_count + 1&lt;br /&gt;
  create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any command-line arguments after ''-code-analysis'' are passed on to &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. This class, in its creation procedure, processes the arguments as described in [[User:Stefan/Code_Analysis/Command Line Usage|Command Line Usage]]. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure &amp;lt;e&amp;gt;execute&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; of course uses the ''code_analysis'' library and the previously described interface of &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;. After analysis a list of rule violations is output to the command-line. In the code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
across l_code_analyzer.rule_violations as l_vlist loop&lt;br /&gt;
  if not l_vlist.item.is_empty then&lt;br /&gt;
    l_has_violations := True&lt;br /&gt;
      -- Always sort the rule violations by the class they are referring to.&lt;br /&gt;
    output_window.add (ca_messages.cmd_class + l_vlist.key.name + &amp;quot;':%N&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting.&lt;br /&gt;
    across l_vlist.item as ic loop&lt;br /&gt;
      l_rule_name := ic.item.rule.title&lt;br /&gt;
      l_rule_id := ic.item.rule.id&lt;br /&gt;
      if attached ic.item.location as l_loc then&lt;br /&gt;
        l_line := ic.item.location.line.out&lt;br /&gt;
        l_col := ic.item.location.column.out&lt;br /&gt;
        output_window.add (&amp;quot;  (&amp;quot; + l_line + &amp;quot;:&amp;quot; + l_col + &amp;quot;): &amp;quot;&lt;br /&gt;
          + l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      else -- No location attached. Print without location.&lt;br /&gt;
        output_window.add (&amp;quot;  &amp;quot;	+ l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      ic.item.format_violation_description (output_window)&lt;br /&gt;
      output_window.add (&amp;quot;%N&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not l_has_violations then output_window.add (ca_messages.no_issues + &amp;quot;%N&amp;quot;) end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15084</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15084"/>
				<updated>2014-03-06T15:52:03Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* Graphical User Interface */ additions&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# 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'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
== ''code_analysis'' library ==&lt;br /&gt;
&lt;br /&gt;
The whole code analysis framework is located in the library ''code_analysis''.&lt;br /&gt;
&lt;br /&gt;
=== Interface ===&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Rule checking ===&lt;br /&gt;
&lt;br /&gt;
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'', &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;. In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt; this task (&amp;lt;e&amp;gt;l_task&amp;lt;/e&amp;gt;) is invoked as follows:&lt;br /&gt;
&lt;br /&gt;
==== In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;: ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed)&lt;br /&gt;
l_task.set_output_actions (output_actions)&lt;br /&gt;
rota.run_task (l_task)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; essentially runs the whole analysis. Like all other conformants to &amp;lt;e&amp;gt;{ROTA_TASK_I}&amp;lt;/e&amp;gt; this class executes a series of ''steps'' between which the user interface gets some time to process its events. In &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; each step analyses one class. This means that a class is checked by ''all'' the rules for violations. The following code does that:&lt;br /&gt;
&lt;br /&gt;
==== From &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;: ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
step&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
  do&lt;br /&gt;
    if has_next_step then&lt;br /&gt;
        -- Gather type information&lt;br /&gt;
      type_recorder.clear&lt;br /&gt;
      type_recorder.analyze_class (classes.item)&lt;br /&gt;
      context.set_node_types (type_recorder.node_types)&lt;br /&gt;
      context.set_checking_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      across rules as l_rules loop&lt;br /&gt;
          -- If rule is non-standard then it will not be checked by l_rules_checker.&lt;br /&gt;
          -- We will have the rule check the current class here:&lt;br /&gt;
        if&lt;br /&gt;
          l_rules.item.is_enabled.value&lt;br /&gt;
          and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule&lt;br /&gt;
        then&lt;br /&gt;
          l_cfg_rule.check_class (classes.item)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
        -- Status output.&lt;br /&gt;
      if output_actions /= Void then&lt;br /&gt;
        output_actions.call ([ca_messages.analyzing_class (classes.item.name)])&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      rules_checker.run_on_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      classes.forth&lt;br /&gt;
      has_next_step := not classes.after&lt;br /&gt;
      if not has_next_step then&lt;br /&gt;
        completed_action.call ([exceptions])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  rescue&lt;br /&gt;
      -- Instant error output.&lt;br /&gt;
    if output_actions /= Void then&lt;br /&gt;
      output_actions.call ([ca_messages.error_on_class (classes.item.name)])&lt;br /&gt;
    end&lt;br /&gt;
    exceptions.extend ([exception_manager.last_exception, classes.item])&lt;br /&gt;
      -- Jump to the next class.&lt;br /&gt;
    classes.forth&lt;br /&gt;
    has_next_step := not classes.after&lt;br /&gt;
    if not has_next_step then&lt;br /&gt;
      completed_action.call ([exceptions])&lt;br /&gt;
    end&lt;br /&gt;
    retry&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;type_recorder&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_AST_TYPE_RECORDER}&amp;lt;/e&amp;gt;. 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. &amp;lt;e&amp;gt;context&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;e&amp;gt;across&amp;lt;/e&amp;gt; loop only checks ''control flow graph rules''. All the ''standard'' rules are checked by the line &amp;lt;e&amp;gt;rules_checker.run_on_class (classes.item)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;rules_checker&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt;. This is the class where each rule must register the AST nodes the rule visits. &amp;lt;e&amp;gt;run_on_class&amp;lt;/e&amp;gt; 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. &amp;lt;e&amp;gt;step&amp;lt;/e&amp;gt; is executed repeatedly until there are no classes left to analyze.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;e&amp;gt;rescue&amp;lt;/e&amp;gt; clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
The classes of the graphical user interface of the code analyzer are all located in the ''interface'' cluster of ''EVE'', in the subfolder ''graphical &amp;gt; tools &amp;gt; code_analysis''. Here is a short overview of what the single classes do:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL}&amp;lt;/e&amp;gt; : Represents the code analysis GUI tool. Contains the tool title and icon, otherwise not much interesting stuff.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL_PANEL}&amp;lt;/e&amp;gt; : The graphical panel for the code analysis tool. It contains buttons, labels, the rule violations table view, and other user interface elements.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; : 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_BENCH_HELPER}&amp;lt;/e&amp;gt; : A helper class for the integration of the code analysis tool. It contains shared instances of &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}&amp;lt;/e&amp;gt; and &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt;, which are used by the GUI.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_SHOW_PREFERENCES_COMMAND}&amp;lt;/e&amp;gt; : The command is used by the ''Preferences'' button in the panel.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_FIX_EXECUTOR}&amp;lt;/e&amp;gt; : This class [[User:Stefan/Code Analysis/Using Analysis Results#Fixing Rule Violations|fixes]] a rule violation that has been found by the code analysis tool.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Caching ===&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;br /&gt;
&lt;br /&gt;
The whole command-line functionality of the code analyzer is located in the class &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. It is located in the ''tty'' cluster of ''EVE''. &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt; is invoked by &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the root class for the ''batch'' (command-line) version of EiffelStudio. In &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the invocation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
elseif option.is_equal (&amp;quot;-code-analysis&amp;quot;) then&lt;br /&gt;
  l_at_args := arguments_in_range (current_option + 1, argument_count)&lt;br /&gt;
  current_option := argument_count + 1&lt;br /&gt;
  create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any command-line arguments after ''-code-analysis'' are passed on to &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. This class, in its creation procedure, processes the arguments as described in [[User:Stefan/Code_Analysis/Command Line Usage|Command Line Usage]]. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure &amp;lt;e&amp;gt;execute&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; of course uses the ''code_analysis'' library and the previously described interface of &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;. After analysis a list of rule violations is output to the command-line. In the code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
across l_code_analyzer.rule_violations as l_vlist loop&lt;br /&gt;
  if not l_vlist.item.is_empty then&lt;br /&gt;
    l_has_violations := True&lt;br /&gt;
      -- Always sort the rule violations by the class they are referring to.&lt;br /&gt;
    output_window.add (ca_messages.cmd_class + l_vlist.key.name + &amp;quot;':%N&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting.&lt;br /&gt;
    across l_vlist.item as ic loop&lt;br /&gt;
      l_rule_name := ic.item.rule.title&lt;br /&gt;
      l_rule_id := ic.item.rule.id&lt;br /&gt;
      if attached ic.item.location as l_loc then&lt;br /&gt;
        l_line := ic.item.location.line.out&lt;br /&gt;
        l_col := ic.item.location.column.out&lt;br /&gt;
        output_window.add (&amp;quot;  (&amp;quot; + l_line + &amp;quot;:&amp;quot; + l_col + &amp;quot;): &amp;quot;&lt;br /&gt;
          + l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      else -- No location attached. Print without location.&lt;br /&gt;
        output_window.add (&amp;quot;  &amp;quot;	+ l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      ic.item.format_violation_description (output_window)&lt;br /&gt;
      output_window.add (&amp;quot;%N&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not l_has_violations then output_window.add (ca_messages.no_issues + &amp;quot;%N&amp;quot;) end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15083</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15083"/>
				<updated>2014-03-06T15:36:10Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* code_analysis library */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# 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'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
== ''code_analysis'' library ==&lt;br /&gt;
&lt;br /&gt;
The whole code analysis framework is located in the library ''code_analysis''.&lt;br /&gt;
&lt;br /&gt;
=== Interface ===&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Rule checking ===&lt;br /&gt;
&lt;br /&gt;
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'', &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;. In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt; this task (&amp;lt;e&amp;gt;l_task&amp;lt;/e&amp;gt;) is invoked as follows:&lt;br /&gt;
&lt;br /&gt;
==== In &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;: ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
create l_task.make (l_rules_checker, l_rules_to_check, classes_to_analyze, agent analysis_completed)&lt;br /&gt;
l_task.set_output_actions (output_actions)&lt;br /&gt;
rota.run_task (l_task)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; essentially runs the whole analysis. Like all other conformants to &amp;lt;e&amp;gt;{ROTA_TASK_I}&amp;lt;/e&amp;gt; this class executes a series of ''steps'' between which the user interface gets some time to process its events. In &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt; each step analyses one class. This means that a class is checked by ''all'' the rules for violations. The following code does that:&lt;br /&gt;
&lt;br /&gt;
==== From &amp;lt;e&amp;gt;{CA_RULE_CHECKING_TASK}&amp;lt;/e&amp;gt;: ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
step&lt;br /&gt;
    -- &amp;lt;Precursor&amp;gt;&lt;br /&gt;
  do&lt;br /&gt;
    if has_next_step then&lt;br /&gt;
        -- Gather type information&lt;br /&gt;
      type_recorder.clear&lt;br /&gt;
      type_recorder.analyze_class (classes.item)&lt;br /&gt;
      context.set_node_types (type_recorder.node_types)&lt;br /&gt;
      context.set_checking_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      across rules as l_rules loop&lt;br /&gt;
          -- If rule is non-standard then it will not be checked by l_rules_checker.&lt;br /&gt;
          -- We will have the rule check the current class here:&lt;br /&gt;
        if&lt;br /&gt;
          l_rules.item.is_enabled.value&lt;br /&gt;
          and then attached {CA_CFG_RULE} l_rules.item as l_cfg_rule&lt;br /&gt;
        then&lt;br /&gt;
          l_cfg_rule.check_class (classes.item)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
        -- Status output.&lt;br /&gt;
      if output_actions /= Void then&lt;br /&gt;
        output_actions.call ([ca_messages.analyzing_class (classes.item.name)])&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      rules_checker.run_on_class (classes.item)&lt;br /&gt;
&lt;br /&gt;
      classes.forth&lt;br /&gt;
      has_next_step := not classes.after&lt;br /&gt;
      if not has_next_step then&lt;br /&gt;
        completed_action.call ([exceptions])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  rescue&lt;br /&gt;
      -- Instant error output.&lt;br /&gt;
    if output_actions /= Void then&lt;br /&gt;
      output_actions.call ([ca_messages.error_on_class (classes.item.name)])&lt;br /&gt;
    end&lt;br /&gt;
    exceptions.extend ([exception_manager.last_exception, classes.item])&lt;br /&gt;
      -- Jump to the next class.&lt;br /&gt;
    classes.forth&lt;br /&gt;
    has_next_step := not classes.after&lt;br /&gt;
    if not has_next_step then&lt;br /&gt;
      completed_action.call ([exceptions])&lt;br /&gt;
    end&lt;br /&gt;
    retry&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;type_recorder&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_AST_TYPE_RECORDER}&amp;lt;/e&amp;gt;. 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. &amp;lt;e&amp;gt;context&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;e&amp;gt;across&amp;lt;/e&amp;gt; loop only checks ''control flow graph rules''. All the ''standard'' rules are checked by the line &amp;lt;e&amp;gt;rules_checker.run_on_class (classes.item)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;rules_checker&amp;lt;/e&amp;gt; has type &amp;lt;e&amp;gt;{CA_ALL_RULES_CHECKER}&amp;lt;/e&amp;gt;. This is the class where each rule must register the AST nodes the rule visits. &amp;lt;e&amp;gt;run_on_class&amp;lt;/e&amp;gt; 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. &amp;lt;e&amp;gt;step&amp;lt;/e&amp;gt; is executed repeatedly until there are no classes left to analyze.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;e&amp;gt;rescue&amp;lt;/e&amp;gt; clause all possible exceptions are caught and recorded. In case of such an exception it then proceeds to the next class.&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
The classes of the graphical user interface of the code analyzer are all located in the ''interface'' cluster of ''EVE'', in the subfolder ''graphical &amp;gt; tools &amp;gt; code_analysis''. Here is a short overview of what the single classes do:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL}&amp;lt;/e&amp;gt; : Represents the code analysis GUI tool. Contains the tool title and icon, otherwise not much interesting stuff.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL_PANEL}&amp;lt;/e&amp;gt; : The graphical panel for the code analysis tool. It contains buttons, labels, the rule violations table view, and other user interface elements.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; : The command to launch the code analyzer. It can be added to toolbars and menus. It can be executed using stones.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_SHOW_PREFERENCES_COMMAND}&amp;lt;/e&amp;gt; : The command is used by the ''Preferences'' button in the panel.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_FIX_EXECUTOR}&amp;lt;/e&amp;gt; : This class [[User:Stefan/Code Analysis/Using Analysis Results#Fixing Rule Violations|fixes]] a rule violation that has been found by the code analysis tool.&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;br /&gt;
&lt;br /&gt;
The whole command-line functionality of the code analyzer is located in the class &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. It is located in the ''tty'' cluster of ''EVE''. &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt; is invoked by &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the root class for the ''batch'' (command-line) version of EiffelStudio. In &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the invocation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
elseif option.is_equal (&amp;quot;-code-analysis&amp;quot;) then&lt;br /&gt;
  l_at_args := arguments_in_range (current_option + 1, argument_count)&lt;br /&gt;
  current_option := argument_count + 1&lt;br /&gt;
  create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any command-line arguments after ''-code-analysis'' are passed on to &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. This class, in its creation procedure, processes the arguments as described in [[User:Stefan/Code_Analysis/Command Line Usage|Command Line Usage]]. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure &amp;lt;e&amp;gt;execute&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; of course uses the ''code_analysis'' library and the previously described interface of &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;. After analysis a list of rule violations is output to the command-line. In the code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
across l_code_analyzer.rule_violations as l_vlist loop&lt;br /&gt;
  if not l_vlist.item.is_empty then&lt;br /&gt;
    l_has_violations := True&lt;br /&gt;
      -- Always sort the rule violations by the class they are referring to.&lt;br /&gt;
    output_window.add (ca_messages.cmd_class + l_vlist.key.name + &amp;quot;':%N&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting.&lt;br /&gt;
    across l_vlist.item as ic loop&lt;br /&gt;
      l_rule_name := ic.item.rule.title&lt;br /&gt;
      l_rule_id := ic.item.rule.id&lt;br /&gt;
      if attached ic.item.location as l_loc then&lt;br /&gt;
        l_line := ic.item.location.line.out&lt;br /&gt;
        l_col := ic.item.location.column.out&lt;br /&gt;
        output_window.add (&amp;quot;  (&amp;quot; + l_line + &amp;quot;:&amp;quot; + l_col + &amp;quot;): &amp;quot;&lt;br /&gt;
          + l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      else -- No location attached. Print without location.&lt;br /&gt;
        output_window.add (&amp;quot;  &amp;quot;	+ l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      ic.item.format_violation_description (output_window)&lt;br /&gt;
      output_window.add (&amp;quot;%N&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not l_has_violations then output_window.add (ca_messages.no_issues + &amp;quot;%N&amp;quot;) end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15082</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15082"/>
				<updated>2014-03-06T14:27:04Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* Graphical User Interface */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# 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'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
== ''code_analysis'' library ==&lt;br /&gt;
&lt;br /&gt;
The whole code analysis framework is located in the library ''code_analysis''.&lt;br /&gt;
&lt;br /&gt;
=== Interface ===&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; to the procedures that are called for outputting 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Rule checking ===&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
The classes of the graphical user interface of the code analyzer are all located in the ''interface'' cluster of ''EVE'', in the subfolder ''graphical &amp;gt; tools &amp;gt; code_analysis''. Here is a short overview of what the single classes do:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL}&amp;lt;/e&amp;gt; : Represents the code analysis GUI tool. Contains the tool title and icon, otherwise not much interesting stuff.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_TOOL_PANEL}&amp;lt;/e&amp;gt; : The graphical panel for the code analysis tool. It contains buttons, labels, the rule violations table view, and other user interface elements.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CODE_ANALYSIS_COMMAND}&amp;lt;/e&amp;gt; : The command to launch the code analyzer. It can be added to toolbars and menus. It can be executed using stones.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_SHOW_PREFERENCES_COMMAND}&amp;lt;/e&amp;gt; : The command is used by the ''Preferences'' button in the panel.&lt;br /&gt;
; &amp;lt;e&amp;gt;{ES_CA_FIX_EXECUTOR}&amp;lt;/e&amp;gt; : This class [[User:Stefan/Code Analysis/Using Analysis Results#Fixing Rule Violations|fixes]] a rule violation that has been found by the code analysis tool.&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;br /&gt;
&lt;br /&gt;
The whole command-line functionality of the code analyzer is located in the class &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. It is located in the ''tty'' cluster of ''EVE''. &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt; is invoked by &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the root class for the ''batch'' (command-line) version of EiffelStudio. In &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the invocation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
elseif option.is_equal (&amp;quot;-code-analysis&amp;quot;) then&lt;br /&gt;
  l_at_args := arguments_in_range (current_option + 1, argument_count)&lt;br /&gt;
  current_option := argument_count + 1&lt;br /&gt;
  create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any command-line arguments after ''-code-analysis'' are passed on to &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. This class, in its creation procedure, processes the arguments as described in [[User:Stefan/Code_Analysis/Command Line Usage|Command Line Usage]]. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure &amp;lt;e&amp;gt;execute&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; of course uses the ''code_analysis'' library and the previously described interface of &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;. After analysis a list of rule violations is output to the command-line. In the code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
across l_code_analyzer.rule_violations as l_vlist loop&lt;br /&gt;
  if not l_vlist.item.is_empty then&lt;br /&gt;
    l_has_violations := True&lt;br /&gt;
      -- Always sort the rule violations by the class they are referring to.&lt;br /&gt;
    output_window.add (ca_messages.cmd_class + l_vlist.key.name + &amp;quot;':%N&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting.&lt;br /&gt;
    across l_vlist.item as ic loop&lt;br /&gt;
      l_rule_name := ic.item.rule.title&lt;br /&gt;
      l_rule_id := ic.item.rule.id&lt;br /&gt;
      if attached ic.item.location as l_loc then&lt;br /&gt;
        l_line := ic.item.location.line.out&lt;br /&gt;
        l_col := ic.item.location.column.out&lt;br /&gt;
        output_window.add (&amp;quot;  (&amp;quot; + l_line + &amp;quot;:&amp;quot; + l_col + &amp;quot;): &amp;quot;&lt;br /&gt;
          + l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      else -- No location attached. Print without location.&lt;br /&gt;
        output_window.add (&amp;quot;  &amp;quot;	+ l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      ic.item.format_violation_description (output_window)&lt;br /&gt;
      output_window.add (&amp;quot;%N&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not l_has_violations then output_window.add (ca_messages.no_issues + &amp;quot;%N&amp;quot;) end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15081</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15081"/>
				<updated>2014-03-06T14:11:02Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: /* Command-line Interface */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# 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'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
== ''code_analysis'' library ==&lt;br /&gt;
&lt;br /&gt;
The whole code analysis framework is located in the library ''code_analysis''.&lt;br /&gt;
&lt;br /&gt;
=== Interface ===&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; to the procedures that are called for outputting 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Rule checking ===&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;br /&gt;
&lt;br /&gt;
The whole command-line functionality of the code analyzer is located in the class &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. It is located in the ''tty'' cluster of ''EVE''. &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt; is invoked by &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the root class for the ''batch'' (command-line) version of EiffelStudio. In &amp;lt;e&amp;gt;{ES}&amp;lt;/e&amp;gt;, the invocation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
elseif option.is_equal (&amp;quot;-code-analysis&amp;quot;) then&lt;br /&gt;
  l_at_args := arguments_in_range (current_option + 1, argument_count)&lt;br /&gt;
  current_option := argument_count + 1&lt;br /&gt;
  create {EWB_CODE_ANALYSIS} command.make_with_arguments (l_at_args)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any command-line arguments after ''-code-analysis'' are passed on to &amp;lt;e&amp;gt;{EWB_CODE_ANALYSIS}&amp;lt;/e&amp;gt;. This class, in its creation procedure, processes the arguments as described in [[User:Stefan/Code_Analysis/Command Line Usage|Command Line Usage]]. Classes that were passed as command-line arguments are added to the analyzer. Then the actual execution happens in the procedure &amp;lt;e&amp;gt;execute&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;EWB_CODE_ANALYSIS&amp;lt;/e&amp;gt; of course uses the ''code_analysis'' library and the previously described interface of &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;. After analysis a list of rule violations is output to the command-line. In the code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
across l_code_analyzer.rule_violations as l_vlist loop&lt;br /&gt;
  if not l_vlist.item.is_empty then&lt;br /&gt;
    l_has_violations := True&lt;br /&gt;
      -- Always sort the rule violations by the class they are referring to.&lt;br /&gt;
    output_window.add (ca_messages.cmd_class + l_vlist.key.name + &amp;quot;':%N&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
      -- See `{CA_RULE_VIOLATION}.is_less' for information on the sorting.&lt;br /&gt;
    across l_vlist.item as ic loop&lt;br /&gt;
      l_rule_name := ic.item.rule.title&lt;br /&gt;
      l_rule_id := ic.item.rule.id&lt;br /&gt;
      if attached ic.item.location as l_loc then&lt;br /&gt;
        l_line := ic.item.location.line.out&lt;br /&gt;
        l_col := ic.item.location.column.out&lt;br /&gt;
        output_window.add (&amp;quot;  (&amp;quot; + l_line + &amp;quot;:&amp;quot; + l_col + &amp;quot;): &amp;quot;&lt;br /&gt;
          + l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      else -- No location attached. Print without location.&lt;br /&gt;
        output_window.add (&amp;quot;  &amp;quot;	+ l_rule_name + &amp;quot; (&amp;quot; + l_rule_id + &amp;quot;): &amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
      ic.item.format_violation_description (output_window)&lt;br /&gt;
      output_window.add (&amp;quot;%N&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not l_has_violations then output_window.add (ca_messages.no_issues + &amp;quot;%N&amp;quot;) end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=User:Stefan&amp;diff=15080</id>
		<title>User:Stefan</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=User:Stefan&amp;diff=15080"/>
				<updated>2014-03-06T13:50:43Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: +link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I am a student of Computer Science at the ETH Zürich, Switzerland. There, for my Master thesis, I am currently working on a [[/Code Analysis/]] tool for EVE (the ETH branch of EiffelStudio). Prior to this I earned my Bachelors degree in Mathematics from the Universität Bern, Switzerland. I also did an IT internship with an airline company.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15079</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15079"/>
				<updated>2014-03-06T13:40:46Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: CA_CODE_ANALYZER interface&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# 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'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
== ''code_analysis'' library ==&lt;br /&gt;
&lt;br /&gt;
The whole code analysis framework is located in the library ''code_analysis''.&lt;br /&gt;
&lt;br /&gt;
=== Interface ===&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_output_action (a_action: attached PROCEDURE [ANY, TUPLE [READABLE_STRING_GENERAL]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; to the procedures that are called for outputting 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;is_rule_checkable (a_rule: attached CA_RULE): BOOLEAN&amp;lt;/e&amp;gt; : Tells whether &amp;lt;e&amp;gt;`a_rule'&amp;lt;/e&amp;gt; will be checked based on the current preferences and based on the current checking scope (whole system or custom set of classes).&lt;br /&gt;
&lt;br /&gt;
Then, to start analyzing simply call &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.analyze&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Rule checking ===&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15078</id>
		<title>CA Adding New Rules</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15078"/>
				<updated>2014-03-06T13:31:00Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Command Line Usage|&amp;amp;lt;&amp;amp;lt; 5. Command Line Usage]] | [[User:Stefan/Code Analysis/Architectural Overview|7. Architectural Overview &amp;amp;gt;&amp;amp;gt;]] &amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
The Code Analysis framework was designed with regard to the fact that '''adding new rules''' should be as simple and as fast as possible. Looking at the initial set of rules that were implemented, nearly all of them have an implementation of less than 200 lines of code. Many of them use even less than 100 lines of code. Rules that search the code for certain patterns (this applies to the vast majority of rules) are particularly simple to implement.&lt;br /&gt;
&lt;br /&gt;
This page shows you how to implement a rule in the form of a class. After you have written such a class you must add the rule to the list of rules. This list is populated in &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.make&amp;lt;/e&amp;gt;. There, just below the lines where all the other rules are added add a line like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;rules.extend (create {YOUR_RULE}.make)&amp;lt;/e&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;e&amp;gt;YOUR_RULE&amp;lt;/e&amp;gt; must be replaced by the name of your rule class and the creation procedure (&amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt;) must be adapted if necessary.&lt;br /&gt;
&lt;br /&gt;
== Standard Rules ==&lt;br /&gt;
&lt;br /&gt;
All rules must conform to &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. The class you implement for a rule is on one hand responsible for checking the rule and contains metadata about the rule (i. e. title, description) on the other hand. As of now, rules must moreover conform to either &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;CA_CFG_RULE&amp;lt;/e&amp;gt;, both of which are subtypes of &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. A large number of possible rules are ''standard rules'', no matter whether they are trivial or more complicated.&lt;br /&gt;
&lt;br /&gt;
All ''Standard rules'' are checked by iterating over the [http://en.wikipedia.org/wiki/Abstract_syntax_tree abstract syntax tree] (AST) of the class code. The developer who adds a new rule can very well ignore the details thereof. He needs to know however which AST nodes his rule needs to process. For each type of AST node you need to add an agent so your routine will be called during the iteration on the AST.&lt;br /&gt;
&lt;br /&gt;
To start implementing your rule you have basically two possibilities. (1) You start from scratch, implementing all deferred features of &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or (2) you use the following template.&lt;br /&gt;
&lt;br /&gt;
=== Standard Rule Template ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
class&lt;br /&gt;
  CA_YOUR_RULE&lt;br /&gt;
&lt;br /&gt;
inherit&lt;br /&gt;
  CA_STANDARD_RULE&lt;br /&gt;
&lt;br /&gt;
create&lt;br /&gt;
  make&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Initialization&lt;br /&gt;
&lt;br /&gt;
  make (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initialization for `Current'.&lt;br /&gt;
    do&lt;br /&gt;
      make_with_defaults&lt;br /&gt;
        -- This initializes the attributes to their default values:&lt;br /&gt;
        -- Severity = warning&lt;br /&gt;
        -- Default Severity Score = 50 (`severity score' can be changed by user)&lt;br /&gt;
        -- Rule enabled by default = True (`Rule enabled' can be changed by user)&lt;br /&gt;
        -- Only for system wide checks = False&lt;br /&gt;
        -- Checks library classes = True&lt;br /&gt;
        -- Checks nonlibrary classes = True&lt;br /&gt;
&lt;br /&gt;
        initialize_options (a_pref_manager)&lt;br /&gt;
&lt;br /&gt;
        -- TODO: Add your initialization here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  initialize_options (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initializes the rule preferences.&lt;br /&gt;
    local&lt;br /&gt;
      l_factory: BASIC_PREFERENCE_FACTORY&lt;br /&gt;
    do&lt;br /&gt;
      create l_factory&lt;br /&gt;
     &lt;br /&gt;
        -- TODO: Add the initialization of your custom preferences here.&lt;br /&gt;
        -- Example:&lt;br /&gt;
--    threshold := l_factory.new_integer_preference_value (a_pref_manager,&lt;br /&gt;
--      preference_namespace + &amp;quot;Threshold&amp;quot;,&lt;br /&gt;
--      30)  -- default value&lt;br /&gt;
--    min_local_name_length.set_default_value (&amp;quot;30&amp;quot;) -- default value, too&lt;br /&gt;
--    min_local_name_length.set_validation_agent (agent is_integer_string_within_bounds (?, 1, 1_000_000))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add agents for the features in section `Rule checking' here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Rule checking&lt;br /&gt;
&lt;br /&gt;
  -- TODO: Add the AST processing here.&lt;br /&gt;
&lt;br /&gt;
feature -- Properties&lt;br /&gt;
&lt;br /&gt;
  title: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the title of your rule here.&lt;br /&gt;
      Result := &amp;quot;(Your title)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- TODO: Add the ID of your rule here. Should be unique!&lt;br /&gt;
  id: STRING_32 = &amp;quot;(YourID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  description: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the rule description here.&lt;br /&gt;
      Result :=  &amp;quot;(Your description)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add a formatted description of a concrete violation of this rule here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let us have a closer look at the various parts of a rule class.&lt;br /&gt;
&lt;br /&gt;
=== Initialization ===&lt;br /&gt;
&lt;br /&gt;
Calling &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt; initializes the attributes to their default values and makes sure that the class invariant is true. If you want to set an attribute to a custom value you can do so by setting it after the call to &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The creation procedure from the template takes an argument of type &amp;lt;e&amp;gt;PREFERENCE_MANAGER&amp;lt;/e&amp;gt;. This is used for initializing preferences that are specific to your rule. Such preferences usually represent integral or boolean values. If you do ''not'' need any custom preferences then you can leave out the argument &amp;lt;e&amp;gt;a_pref_manager&amp;lt;/e&amp;gt; of &amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt; and you can remove the whole &amp;lt;e&amp;gt;initialize_options&amp;lt;/e&amp;gt; feature.&lt;br /&gt;
&lt;br /&gt;
=== AST processing ===&lt;br /&gt;
&lt;br /&gt;
The main part of your rule implementation consists of checking the source code for rule violations. Say, for example, that you want to check &amp;lt;e&amp;gt;if&amp;lt;/e&amp;gt; instructions to have certain properties. Then you would add a feature like &amp;lt;e&amp;gt;process_if (a_if_ast: IF_AS)&amp;lt;/e&amp;gt; to the section ''Rule checking''. Also, you would need to modify the &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt; feature by adding the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;a_checker.add_if_pre_action (agent process_if)&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Of course you may register as many such agents as you want.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
The ''title'' and the ''description'' of the rule may be constant strings, they may also be localized strings. The ''rule ID'' must be unique among all rules. It should not contain spaces and should be reasonably short. The main rules that come with ''Code Analysis'' have IDs that are numbered from CA001 to CA999 (many of which are not used).&lt;br /&gt;
&lt;br /&gt;
=== Formatted Violation Description ===&lt;br /&gt;
&lt;br /&gt;
Your rule should be able to produce a formatted description of a concrete rule violation. This description is for example used in the Code Analysis tool panel of the GUI. There, class names and feature names are enabled for pick-and-drop. Variable names, numbers, and strings will be displayed in a nice way, too. In addition, this description is used in command line mode. In order to produce normal, unformatted text, use &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add&amp;lt;/e&amp;gt;. For adding formatted elements use features like &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_local&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_feature_name&amp;lt;/e&amp;gt; and similar.&lt;br /&gt;
&lt;br /&gt;
You should store all the data you need for this description (variables names, numbers, etc.) in &amp;lt;e&amp;gt;{CA_RULE_VIOLATION}.long_description_info&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;format_violation_description&amp;lt;/e&amp;gt; can then retrieve this data for the formatted output. Here is a simple example of producing a formatted description:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
a_formatter.add (&amp;quot;Feature &amp;quot;)&lt;br /&gt;
if attached {STRING_32} a_violation.long_description_info.first as l_feat_name then&lt;br /&gt;
  a_formatter.add_feature_name (l_feat_name, a_violation.affected_class)&lt;br /&gt;
end&lt;br /&gt;
a_formatter.add (&amp;quot; is very long.&amp;quot;)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== More Customized Rules ==&lt;br /&gt;
&lt;br /&gt;
For rules that do not fit into a simple AST visitor scheme you best inherit your rule from &amp;lt;e&amp;gt;{CA_STANDARD_RULE}&amp;lt;/e&amp;gt;, too. You can for example register agents that get called when a ''class'' or a ''feature'' is processed. Based on these agents you can perform your customized analysis on the classes and/or features. Using ''multiple inheritance'' or just aggregation it should hardly be a problem to include any functionality you need for your analysis.&lt;br /&gt;
&lt;br /&gt;
== Accessing Type Information ==&lt;br /&gt;
&lt;br /&gt;
The AST classes do not contain ''type information''. Suppose your rule processes function calls. Feature calls in the AST do not contain any information on the types, such as the type of the result.&lt;br /&gt;
&lt;br /&gt;
The code analysis framework however provides functionality to retrieve the type of AST nodes. Before the analyzer lets a class be analyzed by all the rules it computes the types of the AST nodes of a class. Hence this data will be available to your rule afterwards.&lt;br /&gt;
&lt;br /&gt;
While your rule is being checked you can retrieve the type of node &amp;lt;e&amp;gt;a_node&amp;lt;/e&amp;gt; from feature &amp;lt;e&amp;gt;a_feature&amp;lt;/e&amp;gt; by calling &amp;lt;e&amp;gt;current_context.node_type (a_node: AST_EIFFEL; a_feature: FEATURE_I)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;{CA_RULE}.current_context&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; and contains other information about current rule checking, too, such as the currently processed class or the matchlist for this class.&lt;br /&gt;
&lt;br /&gt;
== Accessing the Control Flow Graph ==&lt;br /&gt;
&lt;br /&gt;
Some kinds of static code analysis need and use the ''control flow graph'' of a program. The code analysis framework supports rules that use the control flow graph. If there is at least one such rule, the code analyzer computes the control flow graph of the procedures of the analyzed class before letting the ''rule'' check this class.&lt;br /&gt;
&lt;br /&gt;
=== Worklist algorithms ===&lt;br /&gt;
&lt;br /&gt;
''Control flow graph rules'' iterate over the control flow graph. They do it using a ''worklist''—a list of CFG edges that still have to be processed. At the beginning, the worklist contains all edges of the control flow graph. The algorithm will pick edges from the worklist for processing in an arbitrary order. The iteration stops as soon as there are no more edges left in the worklist. How will the worklist get smaller? Each edge that is processed is removed from the worklist. After processing you will have to decide dynamically whether to add all the outgoing (or incoming, depending on the direction) edges to the worklist. Like this you can take the fact into account that some analyses need certain edges to be processed more than once (a fixed point iteration is such an example).&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
A control flow analysis may iterate in either direction. For a forward-directed analysis inherit your rule from &amp;lt;e&amp;gt;{CA_CFG_FORWARD_RULE}&amp;lt;/e&amp;gt;, for a backward analysis use &amp;lt;e&amp;gt;{CA_CFG_BACKWARD_RULE}&amp;lt;/e&amp;gt; instead. In either case you will then have to implement the following deferred features:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;initialize_processing (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; : This is called before a routine is processed using the worklist. Essentially you may use it to initialize and prepare all the data structures you will need during analysis.&lt;br /&gt;
; &amp;lt;e&amp;gt;visit_edge (a_from, a_to: attached CA_CFG_BASIC_BLOCK): BOOLEAN&amp;lt;/e&amp;gt; : This will be called when an edge is being visited. Here, you can put the analysis. If you let &amp;lt;e&amp;gt;Result = False&amp;lt;/e&amp;gt; then no further edges will be added to the worklist. If in contrary you let &amp;lt;e&amp;gt;Result = True&amp;lt;/e&amp;gt; then edges will be added to the worklist: In a ''forward'' analysis all the ''outgoing'' edges of the current one will be added; in a ''backward'' analysis all the ''incoming'' edges will be added.&lt;br /&gt;
&lt;br /&gt;
=== Non-worklist algorithms ===&lt;br /&gt;
&lt;br /&gt;
If your control flow graph does not fit into the structure of an algorithm as described above you may directly inherit from &amp;lt;e&amp;gt;{CA_CFG_RULE}&amp;lt;/e&amp;gt; and implement the feature &amp;lt;e&amp;gt;process_cfg (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; (in addition to the features explained above). In this case you do not have to use a worklist; basically you can process the control flow graph in any way you want.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15077</id>
		<title>CA Adding New Rules</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15077"/>
				<updated>2014-03-06T13:30:08Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Command Line Usage|&amp;amp;lt;&amp;amp;lt; 5. Command Line Usage]] | [[User:Stefan/Code Analysis/Architectural Overview|7. Architectural Overview &amp;amp;gt;&amp;amp;gt;]] &amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
The Code Analysis framework was designed with regard to the fact that '''adding new rules''' should be as simple and as fast as possible. Looking at the initial set of rules that were implemented, nearly all of them have an implementation of less than 200 lines of code. Many of them use even less than 100 lines of code. Rules that search the code for certain patterns (this applies to the vast majority of rules) are particularly simple to implement.&lt;br /&gt;
&lt;br /&gt;
This page shows you how to implement a rule in the form of a class. After you have written such a class you must add the rule to the list of rules. This list is populated in &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.make&amp;lt;/e&amp;gt;. There, just below the lines where all the other rules are added add a line like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;rules.extend (create {YOUR_RULE}.make)&amp;lt;/e&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;e&amp;gt;YOUR_RULE&amp;lt;/e&amp;gt; must be replaced by the name of your rule class and the creation procedure must be adapted if necessary.&lt;br /&gt;
&lt;br /&gt;
== Standard Rules ==&lt;br /&gt;
&lt;br /&gt;
All rules must conform to &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. The class you implement for a rule is on one hand responsible for checking the rule and contains metadata about the rule (i. e. title, description) on the other hand. As of now, rules must moreover conform to either &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;CA_CFG_RULE&amp;lt;/e&amp;gt;, both of which are subtypes of &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. A large number of possible rules are ''standard rules'', no matter whether they are trivial or more complicated.&lt;br /&gt;
&lt;br /&gt;
All ''Standard rules'' are checked by iterating over the [http://en.wikipedia.org/wiki/Abstract_syntax_tree abstract syntax tree] (AST) of the class code. The developer who adds a new rule can very well ignore the details thereof. He needs to know however which AST nodes his rule needs to process. For each type of AST node you need to add an agent so your routine will be called during the iteration on the AST.&lt;br /&gt;
&lt;br /&gt;
To start implementing your rule you have basically two possibilities. (1) You start from scratch, implementing all deferred features of &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or (2) you use the following template.&lt;br /&gt;
&lt;br /&gt;
=== Standard Rule Template ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
class&lt;br /&gt;
  CA_YOUR_RULE&lt;br /&gt;
&lt;br /&gt;
inherit&lt;br /&gt;
  CA_STANDARD_RULE&lt;br /&gt;
&lt;br /&gt;
create&lt;br /&gt;
  make&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Initialization&lt;br /&gt;
&lt;br /&gt;
  make (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initialization for `Current'.&lt;br /&gt;
    do&lt;br /&gt;
      make_with_defaults&lt;br /&gt;
        -- This initializes the attributes to their default values:&lt;br /&gt;
        -- Severity = warning&lt;br /&gt;
        -- Default Severity Score = 50 (`severity score' can be changed by user)&lt;br /&gt;
        -- Rule enabled by default = True (`Rule enabled' can be changed by user)&lt;br /&gt;
        -- Only for system wide checks = False&lt;br /&gt;
        -- Checks library classes = True&lt;br /&gt;
        -- Checks nonlibrary classes = True&lt;br /&gt;
&lt;br /&gt;
        initialize_options (a_pref_manager)&lt;br /&gt;
&lt;br /&gt;
        -- TODO: Add your initialization here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  initialize_options (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initializes the rule preferences.&lt;br /&gt;
    local&lt;br /&gt;
      l_factory: BASIC_PREFERENCE_FACTORY&lt;br /&gt;
    do&lt;br /&gt;
      create l_factory&lt;br /&gt;
     &lt;br /&gt;
        -- TODO: Add the initialization of your custom preferences here.&lt;br /&gt;
        -- Example:&lt;br /&gt;
--    threshold := l_factory.new_integer_preference_value (a_pref_manager,&lt;br /&gt;
--      preference_namespace + &amp;quot;Threshold&amp;quot;,&lt;br /&gt;
--      30)  -- default value&lt;br /&gt;
--    min_local_name_length.set_default_value (&amp;quot;30&amp;quot;) -- default value, too&lt;br /&gt;
--    min_local_name_length.set_validation_agent (agent is_integer_string_within_bounds (?, 1, 1_000_000))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add agents for the features in section `Rule checking' here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Rule checking&lt;br /&gt;
&lt;br /&gt;
  -- TODO: Add the AST processing here.&lt;br /&gt;
&lt;br /&gt;
feature -- Properties&lt;br /&gt;
&lt;br /&gt;
  title: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the title of your rule here.&lt;br /&gt;
      Result := &amp;quot;(Your title)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- TODO: Add the ID of your rule here. Should be unique!&lt;br /&gt;
  id: STRING_32 = &amp;quot;(YourID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  description: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the rule description here.&lt;br /&gt;
      Result :=  &amp;quot;(Your description)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add a formatted description of a concrete violation of this rule here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let us have a closer look at the various parts of a rule class.&lt;br /&gt;
&lt;br /&gt;
=== Initialization ===&lt;br /&gt;
&lt;br /&gt;
Calling &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt; initializes the attributes to their default values and makes sure that the class invariant is true. If you want to set an attribute to a custom value you can do so by setting it after the call to &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The creation procedure from the template takes an argument of type &amp;lt;e&amp;gt;PREFERENCE_MANAGER&amp;lt;/e&amp;gt;. This is used for initializing preferences that are specific to your rule. Such preferences usually represent integral or boolean values. If you do ''not'' need any custom preferences then you can leave out the argument &amp;lt;e&amp;gt;a_pref_manager&amp;lt;/e&amp;gt; of &amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt; and you can remove the whole &amp;lt;e&amp;gt;initialize_options&amp;lt;/e&amp;gt; feature.&lt;br /&gt;
&lt;br /&gt;
=== AST processing ===&lt;br /&gt;
&lt;br /&gt;
The main part of your rule implementation consists of checking the source code for rule violations. Say, for example, that you want to check &amp;lt;e&amp;gt;if&amp;lt;/e&amp;gt; instructions to have certain properties. Then you would add a feature like &amp;lt;e&amp;gt;process_if (a_if_ast: IF_AS)&amp;lt;/e&amp;gt; to the section ''Rule checking''. Also, you would need to modify the &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt; feature by adding the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;a_checker.add_if_pre_action (agent process_if)&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Of course you may register as many such agents as you want.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
The ''title'' and the ''description'' of the rule may be constant strings, they may also be localized strings. The ''rule ID'' must be unique among all rules. It should not contain spaces and should be reasonably short. The main rules that come with ''Code Analysis'' have IDs that are numbered from CA001 to CA999 (many of which are not used).&lt;br /&gt;
&lt;br /&gt;
=== Formatted Violation Description ===&lt;br /&gt;
&lt;br /&gt;
Your rule should be able to produce a formatted description of a concrete rule violation. This description is for example used in the Code Analysis tool panel of the GUI. There, class names and feature names are enabled for pick-and-drop. Variable names, numbers, and strings will be displayed in a nice way, too. In addition, this description is used in command line mode. In order to produce normal, unformatted text, use &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add&amp;lt;/e&amp;gt;. For adding formatted elements use features like &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_local&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_feature_name&amp;lt;/e&amp;gt; and similar.&lt;br /&gt;
&lt;br /&gt;
You should store all the data you need for this description (variables names, numbers, etc.) in &amp;lt;e&amp;gt;{CA_RULE_VIOLATION}.long_description_info&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;format_violation_description&amp;lt;/e&amp;gt; can then retrieve this data for the formatted output. Here is a simple example of producing a formatted description:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
a_formatter.add (&amp;quot;Feature &amp;quot;)&lt;br /&gt;
if attached {STRING_32} a_violation.long_description_info.first as l_feat_name then&lt;br /&gt;
  a_formatter.add_feature_name (l_feat_name, a_violation.affected_class)&lt;br /&gt;
end&lt;br /&gt;
a_formatter.add (&amp;quot; is very long.&amp;quot;)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== More Customized Rules ==&lt;br /&gt;
&lt;br /&gt;
For rules that do not fit into a simple AST visitor scheme you best inherit your rule from &amp;lt;e&amp;gt;{CA_STANDARD_RULE}&amp;lt;/e&amp;gt;, too. You can for example register agents that get called when a ''class'' or a ''feature'' is processed. Based on these agents you can perform your customized analysis on the classes and/or features. Using ''multiple inheritance'' or just aggregation it should hardly be a problem to include any functionality you need for your analysis.&lt;br /&gt;
&lt;br /&gt;
== Accessing Type Information ==&lt;br /&gt;
&lt;br /&gt;
The AST classes do not contain ''type information''. Suppose your rule processes function calls. Feature calls in the AST do not contain any information on the types, such as the type of the result.&lt;br /&gt;
&lt;br /&gt;
The code analysis framework however provides functionality to retrieve the type of AST nodes. Before the analyzer lets a class be analyzed by all the rules it computes the types of the AST nodes of a class. Hence this data will be available to your rule afterwards.&lt;br /&gt;
&lt;br /&gt;
While your rule is being checked you can retrieve the type of node &amp;lt;e&amp;gt;a_node&amp;lt;/e&amp;gt; from feature &amp;lt;e&amp;gt;a_feature&amp;lt;/e&amp;gt; by calling &amp;lt;e&amp;gt;current_context.node_type (a_node: AST_EIFFEL; a_feature: FEATURE_I)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;{CA_RULE}.current_context&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; and contains other information about current rule checking, too, such as the currently processed class or the matchlist for this class.&lt;br /&gt;
&lt;br /&gt;
== Accessing the Control Flow Graph ==&lt;br /&gt;
&lt;br /&gt;
Some kinds of static code analysis need and use the ''control flow graph'' of a program. The code analysis framework supports rules that use the control flow graph. If there is at least one such rule, the code analyzer computes the control flow graph of the procedures of the analyzed class before letting the ''rule'' check this class.&lt;br /&gt;
&lt;br /&gt;
=== Worklist algorithms ===&lt;br /&gt;
&lt;br /&gt;
''Control flow graph rules'' iterate over the control flow graph. They do it using a ''worklist''—a list of CFG edges that still have to be processed. At the beginning, the worklist contains all edges of the control flow graph. The algorithm will pick edges from the worklist for processing in an arbitrary order. The iteration stops as soon as there are no more edges left in the worklist. How will the worklist get smaller? Each edge that is processed is removed from the worklist. After processing you will have to decide dynamically whether to add all the outgoing (or incoming, depending on the direction) edges to the worklist. Like this you can take the fact into account that some analyses need certain edges to be processed more than once (a fixed point iteration is such an example).&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
A control flow analysis may iterate in either direction. For a forward-directed analysis inherit your rule from &amp;lt;e&amp;gt;{CA_CFG_FORWARD_RULE}&amp;lt;/e&amp;gt;, for a backward analysis use &amp;lt;e&amp;gt;{CA_CFG_BACKWARD_RULE}&amp;lt;/e&amp;gt; instead. In either case you will then have to implement the following deferred features:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;initialize_processing (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; : This is called before a routine is processed using the worklist. Essentially you may use it to initialize and prepare all the data structures you will need during analysis.&lt;br /&gt;
; &amp;lt;e&amp;gt;visit_edge (a_from, a_to: attached CA_CFG_BASIC_BLOCK): BOOLEAN&amp;lt;/e&amp;gt; : This will be called when an edge is being visited. Here, you can put the analysis. If you let &amp;lt;e&amp;gt;Result = False&amp;lt;/e&amp;gt; then no further edges will be added to the worklist. If in contrary you let &amp;lt;e&amp;gt;Result = True&amp;lt;/e&amp;gt; then edges will be added to the worklist: In a ''forward'' analysis all the ''outgoing'' edges of the current one will be added; in a ''backward'' analysis all the ''incoming'' edges will be added.&lt;br /&gt;
&lt;br /&gt;
=== Non-worklist algorithms ===&lt;br /&gt;
&lt;br /&gt;
If your control flow graph does not fit into the structure of an algorithm as described above you may directly inherit from &amp;lt;e&amp;gt;{CA_CFG_RULE}&amp;lt;/e&amp;gt; and implement the feature &amp;lt;e&amp;gt;process_cfg (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; (in addition to the features explained above). In this case you do not have to use a worklist; basically you can process the control flow graph in any way you want.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15076</id>
		<title>CA Adding New Rules</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Adding_New_Rules&amp;diff=15076"/>
				<updated>2014-03-06T13:29:32Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: +add the rule to the hardcoded list&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Command Line Usage|&amp;amp;lt;&amp;amp;lt; 5. Command Line Usage]] | [[User:Stefan/Code Analysis/Architectural Overview|7. Architectural Overview &amp;amp;gt;&amp;amp;gt;]] &amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
The Code Analysis framework was designed with regard to the fact that '''adding new rules''' should be as simple and as fast as possible. Looking at the initial set of rules that were implemented, nearly all of them have an implementation of less than 200 lines of code. Many of them use even less than 100 lines of code. Rules that search the code for certain patterns (this applies to the vast majority of rules) are particularly simple to implement.&lt;br /&gt;
&lt;br /&gt;
This page shows you how to implement a rule in the form of a class. After you have written such a class you must add the rule to the list of rules. This list is populated in &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.make&amp;lt;/e&amp;gt;. Just below the lines where all the other rules are added add a line like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;rules.extend (create {YOUR_RULE}.make)&amp;lt;/e&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;e&amp;gt;YOUR_RULE&amp;lt;/e&amp;gt; must be replaced by the name of your rule class and the creation procedure must be adapted if necessary.&lt;br /&gt;
&lt;br /&gt;
== Standard Rules ==&lt;br /&gt;
&lt;br /&gt;
All rules must conform to &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. The class you implement for a rule is on one hand responsible for checking the rule and contains metadata about the rule (i. e. title, description) on the other hand. As of now, rules must moreover conform to either &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or &amp;lt;e&amp;gt;CA_CFG_RULE&amp;lt;/e&amp;gt;, both of which are subtypes of &amp;lt;e&amp;gt;CA_RULE&amp;lt;/e&amp;gt;. A large number of possible rules are ''standard rules'', no matter whether they are trivial or more complicated.&lt;br /&gt;
&lt;br /&gt;
All ''Standard rules'' are checked by iterating over the [http://en.wikipedia.org/wiki/Abstract_syntax_tree abstract syntax tree] (AST) of the class code. The developer who adds a new rule can very well ignore the details thereof. He needs to know however which AST nodes his rule needs to process. For each type of AST node you need to add an agent so your routine will be called during the iteration on the AST.&lt;br /&gt;
&lt;br /&gt;
To start implementing your rule you have basically two possibilities. (1) You start from scratch, implementing all deferred features of &amp;lt;e&amp;gt;CA_STANDARD_RULE&amp;lt;/e&amp;gt; or (2) you use the following template.&lt;br /&gt;
&lt;br /&gt;
=== Standard Rule Template ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
class&lt;br /&gt;
  CA_YOUR_RULE&lt;br /&gt;
&lt;br /&gt;
inherit&lt;br /&gt;
  CA_STANDARD_RULE&lt;br /&gt;
&lt;br /&gt;
create&lt;br /&gt;
  make&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Initialization&lt;br /&gt;
&lt;br /&gt;
  make (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initialization for `Current'.&lt;br /&gt;
    do&lt;br /&gt;
      make_with_defaults&lt;br /&gt;
        -- This initializes the attributes to their default values:&lt;br /&gt;
        -- Severity = warning&lt;br /&gt;
        -- Default Severity Score = 50 (`severity score' can be changed by user)&lt;br /&gt;
        -- Rule enabled by default = True (`Rule enabled' can be changed by user)&lt;br /&gt;
        -- Only for system wide checks = False&lt;br /&gt;
        -- Checks library classes = True&lt;br /&gt;
        -- Checks nonlibrary classes = True&lt;br /&gt;
&lt;br /&gt;
        initialize_options (a_pref_manager)&lt;br /&gt;
&lt;br /&gt;
        -- TODO: Add your initialization here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  initialize_options (a_pref_manager: attached PREFERENCE_MANAGER)&lt;br /&gt;
      -- Initializes the rule preferences.&lt;br /&gt;
    local&lt;br /&gt;
      l_factory: BASIC_PREFERENCE_FACTORY&lt;br /&gt;
    do&lt;br /&gt;
      create l_factory&lt;br /&gt;
     &lt;br /&gt;
        -- TODO: Add the initialization of your custom preferences here.&lt;br /&gt;
        -- Example:&lt;br /&gt;
--    threshold := l_factory.new_integer_preference_value (a_pref_manager,&lt;br /&gt;
--      preference_namespace + &amp;quot;Threshold&amp;quot;,&lt;br /&gt;
--      30)  -- default value&lt;br /&gt;
--    min_local_name_length.set_default_value (&amp;quot;30&amp;quot;) -- default value, too&lt;br /&gt;
--    min_local_name_length.set_validation_agent (agent is_integer_string_within_bounds (?, 1, 1_000_000))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Activation&lt;br /&gt;
&lt;br /&gt;
  register_actions (a_checker: attached CA_ALL_RULES_CHECKER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add agents for the features in section `Rule checking' here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
feature {NONE} -- Rule checking&lt;br /&gt;
&lt;br /&gt;
  -- TODO: Add the AST processing here.&lt;br /&gt;
&lt;br /&gt;
feature -- Properties&lt;br /&gt;
&lt;br /&gt;
  title: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the title of your rule here.&lt;br /&gt;
      Result := &amp;quot;(Your title)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- TODO: Add the ID of your rule here. Should be unique!&lt;br /&gt;
  id: STRING_32 = &amp;quot;(YourID)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  description: STRING_32&lt;br /&gt;
    do&lt;br /&gt;
        -- TODO: Add the rule description here.&lt;br /&gt;
      Result :=  &amp;quot;(Your description)&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
  format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER)&lt;br /&gt;
    do&lt;br /&gt;
      -- TODO: Add a formatted description of a concrete violation of this rule here.&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let us have a closer look at the various parts of a rule class.&lt;br /&gt;
&lt;br /&gt;
=== Initialization ===&lt;br /&gt;
&lt;br /&gt;
Calling &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt; initializes the attributes to their default values and makes sure that the class invariant is true. If you want to set an attribute to a custom value you can do so by setting it after the call to &amp;lt;e&amp;gt;make_with_defaults&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The creation procedure from the template takes an argument of type &amp;lt;e&amp;gt;PREFERENCE_MANAGER&amp;lt;/e&amp;gt;. This is used for initializing preferences that are specific to your rule. Such preferences usually represent integral or boolean values. If you do ''not'' need any custom preferences then you can leave out the argument &amp;lt;e&amp;gt;a_pref_manager&amp;lt;/e&amp;gt; of &amp;lt;e&amp;gt;make&amp;lt;/e&amp;gt; and you can remove the whole &amp;lt;e&amp;gt;initialize_options&amp;lt;/e&amp;gt; feature.&lt;br /&gt;
&lt;br /&gt;
=== AST processing ===&lt;br /&gt;
&lt;br /&gt;
The main part of your rule implementation consists of checking the source code for rule violations. Say, for example, that you want to check &amp;lt;e&amp;gt;if&amp;lt;/e&amp;gt; instructions to have certain properties. Then you would add a feature like &amp;lt;e&amp;gt;process_if (a_if_ast: IF_AS)&amp;lt;/e&amp;gt; to the section ''Rule checking''. Also, you would need to modify the &amp;lt;e&amp;gt;register_actions&amp;lt;/e&amp;gt; feature by adding the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;a_checker.add_if_pre_action (agent process_if)&amp;lt;/e&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Of course you may register as many such agents as you want.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
The ''title'' and the ''description'' of the rule may be constant strings, they may also be localized strings. The ''rule ID'' must be unique among all rules. It should not contain spaces and should be reasonably short. The main rules that come with ''Code Analysis'' have IDs that are numbered from CA001 to CA999 (many of which are not used).&lt;br /&gt;
&lt;br /&gt;
=== Formatted Violation Description ===&lt;br /&gt;
&lt;br /&gt;
Your rule should be able to produce a formatted description of a concrete rule violation. This description is for example used in the Code Analysis tool panel of the GUI. There, class names and feature names are enabled for pick-and-drop. Variable names, numbers, and strings will be displayed in a nice way, too. In addition, this description is used in command line mode. In order to produce normal, unformatted text, use &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add&amp;lt;/e&amp;gt;. For adding formatted elements use features like &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_local&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;{TEXT_FORMATTER}.add_feature_name&amp;lt;/e&amp;gt; and similar.&lt;br /&gt;
&lt;br /&gt;
You should store all the data you need for this description (variables names, numbers, etc.) in &amp;lt;e&amp;gt;{CA_RULE_VIOLATION}.long_description_info&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;format_violation_description&amp;lt;/e&amp;gt; can then retrieve this data for the formatted output. Here is a simple example of producing a formatted description:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;e&amp;gt;&lt;br /&gt;
a_formatter.add (&amp;quot;Feature &amp;quot;)&lt;br /&gt;
if attached {STRING_32} a_violation.long_description_info.first as l_feat_name then&lt;br /&gt;
  a_formatter.add_feature_name (l_feat_name, a_violation.affected_class)&lt;br /&gt;
end&lt;br /&gt;
a_formatter.add (&amp;quot; is very long.&amp;quot;)&lt;br /&gt;
&amp;lt;/e&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== More Customized Rules ==&lt;br /&gt;
&lt;br /&gt;
For rules that do not fit into a simple AST visitor scheme you best inherit your rule from &amp;lt;e&amp;gt;{CA_STANDARD_RULE}&amp;lt;/e&amp;gt;, too. You can for example register agents that get called when a ''class'' or a ''feature'' is processed. Based on these agents you can perform your customized analysis on the classes and/or features. Using ''multiple inheritance'' or just aggregation it should hardly be a problem to include any functionality you need for your analysis.&lt;br /&gt;
&lt;br /&gt;
== Accessing Type Information ==&lt;br /&gt;
&lt;br /&gt;
The AST classes do not contain ''type information''. Suppose your rule processes function calls. Feature calls in the AST do not contain any information on the types, such as the type of the result.&lt;br /&gt;
&lt;br /&gt;
The code analysis framework however provides functionality to retrieve the type of AST nodes. Before the analyzer lets a class be analyzed by all the rules it computes the types of the AST nodes of a class. Hence this data will be available to your rule afterwards.&lt;br /&gt;
&lt;br /&gt;
While your rule is being checked you can retrieve the type of node &amp;lt;e&amp;gt;a_node&amp;lt;/e&amp;gt; from feature &amp;lt;e&amp;gt;a_feature&amp;lt;/e&amp;gt; by calling &amp;lt;e&amp;gt;current_context.node_type (a_node: AST_EIFFEL; a_feature: FEATURE_I)&amp;lt;/e&amp;gt;. &amp;lt;e&amp;gt;{CA_RULE}.current_context&amp;lt;/e&amp;gt; is of type &amp;lt;e&amp;gt;{CA_ANALYSIS_CONTEXT}&amp;lt;/e&amp;gt; and contains other information about current rule checking, too, such as the currently processed class or the matchlist for this class.&lt;br /&gt;
&lt;br /&gt;
== Accessing the Control Flow Graph ==&lt;br /&gt;
&lt;br /&gt;
Some kinds of static code analysis need and use the ''control flow graph'' of a program. The code analysis framework supports rules that use the control flow graph. If there is at least one such rule, the code analyzer computes the control flow graph of the procedures of the analyzed class before letting the ''rule'' check this class.&lt;br /&gt;
&lt;br /&gt;
=== Worklist algorithms ===&lt;br /&gt;
&lt;br /&gt;
''Control flow graph rules'' iterate over the control flow graph. They do it using a ''worklist''—a list of CFG edges that still have to be processed. At the beginning, the worklist contains all edges of the control flow graph. The algorithm will pick edges from the worklist for processing in an arbitrary order. The iteration stops as soon as there are no more edges left in the worklist. How will the worklist get smaller? Each edge that is processed is removed from the worklist. After processing you will have to decide dynamically whether to add all the outgoing (or incoming, depending on the direction) edges to the worklist. Like this you can take the fact into account that some analyses need certain edges to be processed more than once (a fixed point iteration is such an example).&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
&lt;br /&gt;
A control flow analysis may iterate in either direction. For a forward-directed analysis inherit your rule from &amp;lt;e&amp;gt;{CA_CFG_FORWARD_RULE}&amp;lt;/e&amp;gt;, for a backward analysis use &amp;lt;e&amp;gt;{CA_CFG_BACKWARD_RULE}&amp;lt;/e&amp;gt; instead. In either case you will then have to implement the following deferred features:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;e&amp;gt;initialize_processing (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; : This is called before a routine is processed using the worklist. Essentially you may use it to initialize and prepare all the data structures you will need during analysis.&lt;br /&gt;
; &amp;lt;e&amp;gt;visit_edge (a_from, a_to: attached CA_CFG_BASIC_BLOCK): BOOLEAN&amp;lt;/e&amp;gt; : This will be called when an edge is being visited. Here, you can put the analysis. If you let &amp;lt;e&amp;gt;Result = False&amp;lt;/e&amp;gt; then no further edges will be added to the worklist. If in contrary you let &amp;lt;e&amp;gt;Result = True&amp;lt;/e&amp;gt; then edges will be added to the worklist: In a ''forward'' analysis all the ''outgoing'' edges of the current one will be added; in a ''backward'' analysis all the ''incoming'' edges will be added.&lt;br /&gt;
&lt;br /&gt;
=== Non-worklist algorithms ===&lt;br /&gt;
&lt;br /&gt;
If your control flow graph does not fit into the structure of an algorithm as described above you may directly inherit from &amp;lt;e&amp;gt;{CA_CFG_RULE}&amp;lt;/e&amp;gt; and implement the feature &amp;lt;e&amp;gt;process_cfg (a_cfg: attached CA_CONTROL_FLOW_GRAPH)&amp;lt;/e&amp;gt; (in addition to the features explained above). In this case you do not have to use a worklist; basically you can process the control flow graph in any way you want.&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15073</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15073"/>
				<updated>2014-03-06T13:01:35Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# 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'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
== ''code_analysis'' library ==&lt;br /&gt;
&lt;br /&gt;
The whole code analysis framework is located in the library ''code_analysis''.&lt;br /&gt;
&lt;br /&gt;
=== Interface ===&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_cluster (a_cluster: attached CLUSTER_I)&amp;lt;/e&amp;gt; : Adds all classes of a cluster (and all the classes of the sub-clusters recursively).&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_group (a_group: attached CONF_GROUP)&amp;lt;/e&amp;gt; : Adds all classes of a configuration group. An example of a configuration group is a ''library''.&lt;br /&gt;
&lt;br /&gt;
Here are other features which can be called before starting to analyze:&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.clear_classes_to_analyze&amp;lt;/e&amp;gt; : Removes all classes that have been added to the list of classes to analyze.&lt;br /&gt;
; &amp;lt;e&amp;gt;add_completed_action (a_action: attached PROCEDURE [ANY, TUPLE [ITERABLE [TUPLE [detachable EXCEPTION, CLASS_C]]]])&amp;lt;/e&amp;gt; : Adds &amp;lt;e&amp;gt;`a_action'&amp;lt;/e&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
=== Rule checking ===&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15072</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15072"/>
				<updated>2014-03-06T11:56:41Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: intermediate initial version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code for Code Analysis is located at three different places in the ''EVE'' source:&lt;br /&gt;
# 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'';&lt;br /&gt;
# The graphical user interface can be found in the ''interface'' cluster of ''EVE'';&lt;br /&gt;
# The command-line interface for code analysis is a single class in the ''tty'' cluster of ''EVE''.&lt;br /&gt;
&lt;br /&gt;
== ''code_analysis'' library ==&lt;br /&gt;
&lt;br /&gt;
The whole code analysis framework is located in the library ''code_analysis''.&lt;br /&gt;
&lt;br /&gt;
=== Interface ===&lt;br /&gt;
&lt;br /&gt;
In this section it is explained from a client view how to use the code analyzer. The code analyzer is represented by the class &amp;lt;e&amp;gt;CA_CODE_ANALYZER&amp;lt;/e&amp;gt;, 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.&lt;br /&gt;
; &amp;lt;e&amp;gt;{CA_CODE_ANALYZER}.add_whole_system&amp;lt;/e&amp;gt; : 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 &amp;lt;e&amp;gt;MY_MAIN&amp;lt;/e&amp;gt;, &amp;lt;e&amp;gt;MY_BOX&amp;lt;/e&amp;gt;, and &amp;lt;e&amp;gt;MY_ITEM&amp;lt;/e&amp;gt; then these three classes will be added to the list of classes to be analyzed.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_class (a_class: attached CONF_CLASS)&amp;lt;/e&amp;gt; : Adds a single class.&lt;br /&gt;
; &amp;lt;e&amp;gt;.add_classes (a_classes: attached ITERABLE [attached CONF_CLASS])&amp;lt;/e&amp;gt; : Adds a list of classes.&lt;br /&gt;
&lt;br /&gt;
=== Rule checking ===&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15057</id>
		<title>CA Library Implementation</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=CA_Library_Implementation&amp;diff=15057"/>
				<updated>2014-02-18T15:50:23Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: draft&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&amp;lt;small&amp;gt;[[User:Stefan/Code Analysis/Adding New Rules|&amp;amp;lt;&amp;amp;lt; 6. Adding New Rules]] |&amp;lt;/small&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ''code_analysis'' library ==&lt;br /&gt;
&lt;br /&gt;
=== Rule checking ===&lt;br /&gt;
&lt;br /&gt;
== Graphical User Interface ==&lt;br /&gt;
&lt;br /&gt;
== Command-line Interface ==&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=User:Stefan/Code_Analysis/Screenshots&amp;diff=15056</id>
		<title>User:Stefan/Code Analysis/Screenshots</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=User:Stefan/Code_Analysis/Screenshots&amp;diff=15056"/>
				<updated>2014-02-18T15:48:06Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: Initial version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:CA Sample Results.png|thumb|center|700px|Analysis results (GUI)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Ca empty-tool-panel.png|thumb|center|700px|The tool panel]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:CA Console Code Analysis Results.png|thumb|center|700px|Console Output]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:CA Preferences Dialog.png|thumb|center|700px|Preferences]]&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:CA_Fixing.png&amp;diff=15052</id>
		<title>File:CA Fixing.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:CA_Fixing.png&amp;diff=15052"/>
				<updated>2014-02-18T13:31:19Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:CA_Rule_Preferences.png&amp;diff=15051</id>
		<title>File:CA Rule Preferences.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:CA_Rule_Preferences.png&amp;diff=15051"/>
				<updated>2014-02-18T13:30:52Z</updated>
		
		<summary type="html">&lt;p&gt;Stefan: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Stefan</name></author>	</entry>

	</feed>