Difference between revisions of "CA Adding New Rules"
(→Formatted Violation Description) |
(→Accessing the Control Flow Graph) |
||
Line 140: | Line 140: | ||
== Accessing the Control Flow Graph == | == Accessing the Control Flow Graph == | ||
+ | |||
+ | Some kinds of static code analysis needs and uses 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, it computes the control flow graph of the procedures of the analyzed classes. |
Revision as of 01:04, 18 February 2014
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.
Contents
Standard Rules
All rules must conform to CA_RULE
. 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 CA_STANDARD_RULE
or CA_CFG_RULE
, both of which are subtypes of CA_RULE
. A large number of possible rules are standard rules, no matter whether they are trivial or more complicated.
All Standard rules are checked by iterating over the 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.
To start implementing your rule you have basically two possibilities. (1) You start from scratch, implementing all deferred features of CA_STANDARD_RULE
or (2) you use the following template.
Standard Rule Template
class CA_YOUR_RULE inherit CA_STANDARD_RULE create make feature {NONE} -- Initialization make (a_pref_manager: attached PREFERENCE_MANAGER) -- Initialization for `Current'. do make_with_defaults -- This initializes the attributes to their default values: -- Severity = warning -- Default Severity Score = 50 (`severity score' can be changed by user) -- Rule enabled by default = True (`Rule enabled' can be changed by user) -- Only for system wide checks = False -- Checks library classes = True -- Checks nonlibrary classes = True initialize_options (a_pref_manager) -- TODO: Add your initialization here. end initialize_options (a_pref_manager: attached PREFERENCE_MANAGER) -- Initializes the rule preferences. local l_factory: BASIC_PREFERENCE_FACTORY do create l_factory -- TODO: Add the initialization of your custom preferences here. -- Example: -- threshold := l_factory.new_integer_preference_value (a_pref_manager, -- preference_namespace + "Threshold", -- 30) -- default value -- min_local_name_length.set_default_value ("30") -- default value, too -- min_local_name_length.set_validation_agent (agent is_integer_string_within_bounds (?, 1, 1_000_000)) end feature {NONE} -- Activation register_actions (a_checker: attached CA_ALL_RULES_CHECKER) do -- TODO: Add agents for the features in section `Rule checking' here. end feature {NONE} -- Rule checking -- TODO: Add the AST processing here. feature -- Properties title: STRING_32 do -- TODO: Add the title of your rule here. Result := "(Your title)" end -- TODO: Add the ID of your rule here. Should be unique! id: STRING_32 = "(YourID)" description: STRING_32 do -- TODO: Add the rule description here. Result := "(Your description)" end format_violation_description (a_violation: attached CA_RULE_VIOLATION; a_formatter: attached TEXT_FORMATTER) do -- TODO: Add a formatted description of a concrete violation of this rule here. end end
Let us have a closer look at the various parts of a rule class.
Initialization
Calling make_with_defaults
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 make_with_defaults
.
The creation procedure from the template takes an argument of type PREFERENCE_MANAGER
. 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 a_pref_manager
of make
and you can remove the whole initialize_options
feature.
AST processing
The main part of your rule implementation consists of checking the source code for rule violations. Say, for example, that you want to check if
instructions to have certain properties. Then you would add a feature like process_if (a_if_ast: IF_AS)
to the section Rule checking. Also, you would need to modify the register_actions
feature by adding the line
a_checker.add_if_pre_action (agent process_if)
.
Of course you may register as many such agents as you want.
Properties
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).
Formatted Violation Description
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 {TEXT_FORMATTER}.add
. For adding formatted elements use features like {TEXT_FORMATTER}.add_local
, {TEXT_FORMATTER}.add_feature_name
and similar.
You should store all the data you need for this description (variables names, numbers, etc.) in {CA_RULE_VIOLATION}.long_description_info
. format_violation_description
can then retrieve this data for the formatted output. Here is a simple example of producing a formatted description:
a_formatter.add ("Feature ") if attached {STRING_32} a_violation.long_description_info.first as l_feat_name then a_formatter.add_feature_name (l_feat_name, a_violation.affected_class) end a_formatter.add (" is very long.")
More Customized Rules
Accessing Type Information
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.
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.
While your rule is being checked you can retrieve the type of node a_node
from feature a_feature
by calling current_context.node_type (a_node: AST_EIFFEL; a_feature: FEATURE_I)
. {CA_RULE}.current_context
is of type {CA_ANALYSIS_CONTEXT}
and contains other information about current rule checking, too, such as the currently processed class or the matchlist for this class.
Accessing the Control Flow Graph
Some kinds of static code analysis needs and uses 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, it computes the control flow graph of the procedures of the analyzed classes.