Getting started
Pre-requisites

We will use oug to launch commands in a shell. Therefore we suppose that Oug is installed and oug is in a directory of the PATH environment variable.

The code to analyse must be compiled, because Oug performs various analysis of the OCaml compiler (all stages up to the typing stage) and to do so needs the compiled interfaces of the used modules.

Introduction

Oug analyses the given OCaml source files and builds a graph with "holes" for each source file. Then, these graphs are gathered into a global graph. This allow to re-analyse only source files which changed since the previous analysis. It is no longer necessary to given source files in their dependency order.

Another point is that one must give Oug the same options used to compile the source files, like the -I and -pp options (see this section).

One can indicate to the tool the interface files (.mli), this will create export edges in the graph, giving explicitly useful elements.

Rather than analyse the source files each time we want to search something in the global graph, it is better (because faster) to create a dump of the graph once built and load this graph to perform the needed searches. This is the method explained below.

Building and dumping the global graph

The --dump option allows to store the global graph with the analysis environment. This is useful to perform incremental analysis, for example when some source files need different -pp options. In this case, we proceed the following way:

# oug --dump tmp.oug -pp command1 file1.ml
# oug --load tmp.oug --dump tmp.oug -pp command2 file2.ml
# ...

By default, the graph stored in the file tmp.oug by this command is reduced, that is the expression nodes are removed from the graph, except idents. To prevent this reduction and keep the complete graph (with all expression nodes) we will use the --no-reduce option to store, with the command below, the non-reduced graph in the graph.oug file:

# oug --no-reduce --dump graph.oug -I foo -I +bar file1.ml file2.ml ...

Of course, all these commands can be put in a Makefile, for example with the stored graph depending on the source files.

Looking for useless elements

The analysis of the graph to find useless elements is triggered by the --useless option of oug, with a filename to store this list, in text format:

# oug --load graph.oug --no-reduce --useless useless.txt

The --no-reduce option indicates not to reduce the graph before the analysis. Since this analysis can take somes minutes to complete when the graph contains thousands of elements, we will use the --progress option to display the progress.

Here is an exemple of result:

...
File "oug_data.ml", line 505, char 56:
in_mod_id [p]
File "oug_data.ml", line 583, char 25:
functor_env [v]
File "oug_data.ml", line 583, char 38:
functor_args [v]
File "oug_data.ml", line 808, char 4:
Oug_data.orig_mod_list [v]
File "oug_data.ml", line 880, char 24:
modname [p]
...

The character between brackets next to of each element name is the kind of the element: (v)alue, (M)odule, (t)ype, (C)lass, type (f)ield, (m)ethod, (i)nstance variable, (p)attern ident, (e)xpression.

Filtering

Filters allow to select elements of the graph, to perform some searches. The language of filters and examples are described in section filters.

Two options of oug allow to use a filter:

  • --filter <f>: applies the filter f to the graph and displays on standard output the elements matching this filter,
  • --keep <f>: applies the filter f to the graph and keeps only the elements matching the filter and edges between these elements. The new graph is used in the next actions.

Then it is possible to perform various actions one after another (see section actions) by using these options:

# oug --load graph.oug --filter "<Foo.*>" --keep "v:<*>" \
  --dump tmp.oug --filter "<Foo.a*>"

The command above performs the following actions, in this order:

  • load the graph from the file graph.oug,
  • display the elements matching the filter "<Foo.*>",
  • keep only the elements which are values,
  • store the new graph in the file tmp.oug,
  • from the new graph, display the elements matching the filter "<Foo.a*>".

Filters can be applied on the reduced graph or on the complete graph.

Here are two examples of useful filters which can be used on the global graph. The first one lists the variant constructors not used to create a value:

oug --load graph.oug --filter "f:<*> & ! (<*> -create->)" 

The second one lists the record fields never read:

oug --load graph.oug --filter "f:<*> & ! (<*> -use->)" 

These two filters give the intended results under two assumptions:

  • all variant constructors are explicitly matched somewhere in the code (to avoid that one of them appears "not used"),
  • a value of a variant type is never tested by applying a comparison function with a value of the same type built only for this purpose, like in if x = None then ....
Toplevel
To be completed...
Graphical toplevel
To be completed...