Code Review Module - Coder

Last updated on
4 November 2021

This documentation needs review. See "Help improve this page" in the sidebar.

Coder is the code review module. The name coder has a double meaning: a "coder" is obviously someone who writes code, and "code-r" is short for "code review".

Coder Sniffer is the part of Coder that can be run standalone from the command line and can be integrated with many IDEs.

User Reference for Coder module in D7 and D6

For Coder Upgrade, the latter includes the Grammar Parser and Libraries API. As a developer tool, this project is not like a "typical" project for which you generally want the "recommended" releases on a production site. As a rule, the development releases of this project and its supporting projects are stable and meant to work together.

Drupal 6 and earlier versions

The Drupal 6.x and earlier versions are no longer supported. That means that you can use them and they still should be useful, but if you find any problems with them, there is no point raising an issue about them. If you really want to have support, then you will have to upgrade to Drupal 7 and use the 7.x version of the module. Alternatively, you can install drush and install coder as a drush plugin, and then you can get the latest coder review results on a 6.x code base.

Developer Tools

The Coder project includes two developer modules that assist with code review (Coder Review maintained by douggreen and stella) and code manipulation (Coder Upgrade maintained by solotandem). Each of the modules supports a plug-in extensible hook system so contributed modules can define additional review standards and upgrade routines.

Live Site
From the live site, you can upload your module code and run Coder Upgrade followed by Coder Review (on the upgraded code). In return, you get clean, standards-compliant code (from the Grammar Parser output) and a jump start on your module conversion. You can even convert SQL to the new object-based DB API with the SQL conversion tool on this site.

Coder Review

This module utilizes rules (mostly regular expressions) to review source code files for code that 1) needs to change due to Drupal API changes and 2) does not satisfy Drupal coding standards.

Coder Review provides support for:

The following modules extend the reviews available in the Coder Review module:

Coder Upgrade

This module utilizes the Grammar Parser library to modify a source code file based on its grammar. The module utilizes the growing API for code manipulation (e.g., getting, setting, inserting and deleting parameters to a function call) provided by the Grammar Parser library to modify source code in a precise and programmatic fashion. The module utilizes the familiar Drupal hook system to invoke upgrade routines (e.g., for function calls and hook functions), allowing other modules to enhance or modify a routine. Contributed modules that define an API can develop upgrade routines that would enable other contributed modules relying on that API to upgrade their code.

Coder Upgrade outputs:

  • the modified source code file (with an option 1) to copy and overwrite the original file, or 2) to leave the original file unchanged and write the modified file to the output directory)
  • a patch file that can be more easily reviewed for the changes made and also submitted in an issue queue.

An example (the issue is still being debated, however) of an upgrade routine to modify Drupal core files is this one for SimpleTest test files. A recent example of modifying a custom API is shown here.

The 7.x branch requires:

Review and Rule Developer References

Reviews

A review is a set of rules designed to accomplish a task. There is a code standards review, a review for upgrading from 4.7.x->5.x, another review for upgrading from 5.x->6.x, there's the beginnings of a security review and a performance review. Each review has an array of rules. The reviews are shown on the UI pages and can be found in the includes directory.

Options

  • #title
  • #link - link to drupal.org page about the review
  • #rules - rule definition (see below)
  • #severity - default severity (minor, normal, critical) for all rules in the review. severity controls the color and icons displayed. this value can be over-riden by individual rules.

Rules

A rule is a single specific pattern to find. Rules can use the following #type:

  • regex - look for a particular pattern
  • grep - looks for a particular string, meant to be faster when regex is not needed
  • grep_invert - look for a particular string that does not exist
  • callback - do anything you want

More about regex rules

Thus, to find all _submit functions you could use

    array(
      '#type' => 'regex',
      '#value' => '_submit\s*\(',
    ),

This example regex looks for _submit followed by optional spaces, and a required left parenthesis. If you wanted to be more specific, since the _submit handler has very specific arguments that are changing, you could look for:

      '#value' => '_submit\s*\(\$form_id,',

Remember, coder is just a helpful tool. It's not going to catch every use-case (people who use different variable names), but a simple rule like this will find all 5.x submit handlers and warn you to upgrade it. If you wanted to be more generic, you could write a rule that looked for two arguments instead of 3, but the regex for that is a little harder.

You can also restrict your regex searches within a function. So, if you wanted to warn about the recent menu changes:

    array(
      '#type' => 'regex',
      '#function' => '_menu$',
      '#value' => '\$items\[\]\s*=|if\s*\(\$may_cache\)',
    ),

This rule looks for $items[] = or if ($may_cache).

Quoted strings are replaced with '' in the php source (the default, but see below). Thus if you wanted to make sure that the above had a string array index (such as $items['something'] =, you could have written (BTW, this is a bogus example just to show quoted strings):

    array(
      '#type' => 'regex',
      '#value' => '\$items\[\'\'\]\s*=',
    ),

Rule warnings

Finding code patterns is only half the problem. You also need to write a warning. There are two warning options,

  1. #warning
  2. #warning_callback

So, using the first example above, we should add a warning

      '#value' => '_submit\s*\(\$form_id,',
      '#warning' => t('hook_submit() parameters have changed'),

Notice that this warning uses t for text processing. Since this function takes processing time, and since the rules files are read a lot, there also exists a warning_callback that should be used in most cases. So, the above really should be:

      '#value' => '_submit\s*\(\$form_id,',
      '#warning_callback' => '_coder_6x_fapi_submit_warning',
...
  functions _coder_6x_fapi_submit_warning() {
    return t('!hook_submit() parameters have changed',
      array(
        '!hook_submit' => theme('drupalapi', 'hook_submit'),
      )
    );
  }
Warning Callbacks

Warning callbacks support either a text string or an array. If an array is returned, it should contain:

  • #warning - this is the same as the simple text string (or #warning in the rule)
  • #description - a more detailed description. if supplied, the user can click on the down-arrow icon and receive more information about this warning
  • #link - link to more Detailed documentation, usually on d.o.

Available source options

Usually, you're just looking for something in the php. But coder supports these #source options:

  • php - this is the default
  • allphp - similar to php option, but also includes full quotes
  • html - anything not inside <?php ... ?>, but also looks for html tags inside quotes.
  • all - any line in the source. this is sometimes needed to override the default quote and/or comment handling.
  • quote - anything inside a single (') or double-quote (")
  • doublequote - anything inside a double-quote (")
  • comment - anything inside a comment, including the leading and trailing comment

So, for example, if you want to look for the string "hello world" (inside a doublequote), you can use the following:

    array(
      '#type' => 'regex',
      '#value' => 'hello world',
      '#source' => 'doublequote',
    ),

It should be noted that there isn't a 'comment' option and there probably should be. The only way to search for comments is to use '#source' option 'all'. Otherwise, all comments are stripped.

Other rules options

  • #case-sensitive - pattern matching ignores case by default. Use this to for case sensitive matching. This is needed for camelCase and capitalization rules.
  • #not - to make pattern matching rules simpler, use this to exclude matched values
  • #never - never match lines that also contain this regex (uses #source = all)
  • #severity - severity (minor, normal, critical) controls the color and icons displayed. values defined here over-ride values set in the review
  • #filename - apply this rule to files whose filename matches a regex
  • #filename-not - apply this rule to files whose filename does not match a regex

Ignore system

It is preferable to fix invalid warnings, but if coder is throwing invalid warnings, you can tell coder to ignore the warning in your code using a comment. In the UI, each warning now displays along with it's warning name. You can also enable warnings from the drush command line, see drush coder --ignorename.

A few quick examples:

This is comment scope:

// @ignore rule:comment
/*
 * Let's assume that this line is OK
 *
 * But way down here, maybe,
 * This is a comment that has some valid stuff in it that coder flags................................
 **/

This would also work for coder, but would likely have doxygen problems:

/*
 * @ignore rule:comment
 * Let's assume that this line is OK
 *
 * But way down here, maybe,
 * This is a comment that has some valid stuff in it that coder flags................................
 **/

This is a function scope:

$a = 'nothing ignored yet';

/**
 * My function
 */
function my_function() {
  // @ignore rule:function
  $b = 'the rule is ignored';
}

$c = 'the rule is no longer ignored';

function your_function() {
  $d = 'of course the rule is not ignored here either';
}

You can also enable function (or class scope) from anywhere within the function and class.

class MyClass {
  // @ignore rule:class
  protected function yourFunction() {
    $b = 'the rule is ignored here';
  }

  protected $c = 'the rule is also ignored here';
};

function another_function() {
  $d = 'the rule is not ignored here because we are outside the class now';
}

class AnotherClass {
  protected $a = 'nothing is ignored yet';

  function myFunction() {
    $b = 'the rule is not ignored here';
  }

  // @ignore rule:class

  protected function yourFunction() {
    $b = 'the rule is ignored here';
  }

  protected $c = 'the rule is also ignored here';
};

function another_function() {
  $d = 'the rule is not ignored here because we are outside the class now';
}

Help improve this page

Page status: Needs review

You can: