   Once the most frequent match is identified, the `Collector` looks up
   source files that have other matches (e.g. both :with_space
   and :without_space or just :without_space when :with_space is the
-  most frequent) and calls the `issue_formatter` on them (see below).
+  most frequent) and calls the `issue_formatter` function on them.
 
-  `issue_formatter` functions may call `find_locations_not_matching`
-  to obtain additional metadata for each occurrence of
+  An issue formatter produces a list of `Credo.Issue` structs
+  from the most frequent (expected) match, a source file
+  containing other matches, and check params
+  (the latter two are required to build an IssueMeta).
+  """
+  @type issue_formatter :: (term, SourceFile.t, Keyword.t -> [Issue.t])
+
+  @doc """
+  `issue_formatter` may call the `@collector.find_locations_not_matching/2`
+  function to obtain additional metadata for each occurrence of
   an unexpected match in a given file.
+
+  An example implementation that returns a list of line numbers on
+  which unexpected occurrences were found:
+
+      def find_locations_not_matching(expected, source_file) do
+        traverse(source_file, fn(match, line_no, acc) ->
+          if match != expected, do: acc ++ [line_no], else: acc
+        end)
+      end
+
+      defp traverse(source_file, fun), do: ...
   """
   @callback find_locations_not_matching(
     expected :: term, source_file :: SourceFile.t) :: list(term)
 
   @optional_callbacks find_locations_not_matching: 2
-
-  @doc """
-  An issue formatter produces a list of `Credo.Issue` structs
-  from an expected match, a source file with unexpected matches,
-  and check params (the latter two are required to build an IssueMeta).
-  """
-  @type issue_formatter :: (term, SourceFile.t, Keyword.t -> [Issue.t])
 
   defmacro __using__(_opts) do
     quote do

  alias Credo.Execution.Issues

  @doc """
  The first step of a `Collector` run is counting occurrences of matches
  (e.g. :with_space and :without_space for a space around operators check).

  This function produces a map of matches as keys and their frequencies
  as values (e.g. %{with_space: 50, without_space: 40}) for a single source
  file.

  The maps for individual source files are then merged, producing a map
  that reflects frequency trends for the whole codebase.

defmodule Credo.Check.Consistency.Collector do
  @moduledoc """
  A behavior for modules that walk through source files and
  identify consistency issues.

  When defining a consistency check, you would typically use
  this structure for the main module, responsible
  for formatting issue messages:

      defmodule Credo.Check.Consistency.SomeCheck do
        use Credo.Check, run_on_all: true

        @collector Credo.Check.Consistency.SomeCheck.Collector

        def run(source_files, exec, params \\ []) when is_list(source_files) do
          issue_formatter = &issues_for/3
          @collector.create_issues(source_files, exec, params, issue_formatter)
        end

        defp issues_for(expected, source_file, params) do
          issue_meta = IssueMeta.for(source_file, params)
          issue_locations =
            @collector.find_locations_not_matching(expected, source_file)

          Enum.map(issue_locations, fn(location) ->
            format_issue issue_meta, message: ... # write an issue message
          end)
        end

  The actual analysis would be performed by another module
  implementing the `Credo.Check.Consistency.Collector` behavior:

      defmodule Credo.Check.Consistency.SomeCheck.Collector do
        use Credo.Check.Consistency.Collector

        def collect_matches(source_file, params), do ...

        def find_locations_not_matching(expected, source_file), do ...
      end

  Read further for more information on `collect_matches/2`,
  `find_locations_not_matching/2`, and `issue_formatter`.
  """

  alias Credo.Issue
