Page
Library
Module
Module type
Parameter
Class
Class type
Source
Program analysis for OCaml projects built with dune:
Early release. While the core functionality is reasonably stable, the CLI and annotations are subject to change. However, this is a tiny surface at the moment.
The rest of this document describes the dead code analysis. For the Exception Analysis, build instructions are the same, and the command-line invocation is different.
Build and run on existing projects using the Build and Try instructions below. The analysis uses .cmt[i] files which are generated during compilation, so should be run after building your project. Remember to rebuild the project before running again.
# dead code analysis
reanalyze.exe -dce-cmt root/containing/cmt/files
# exception analysis
reanalyze.exe -exception-cmt root/containing/cmt/filesSubdirectories are scanned recursively looking for .cmt[i] files.
The requirement is that the current directory is where file paths start from. So if the file path seen by the compiler is relative src/core/version.ml then the current directory should contain src as a subdirectory. The analysis only reports on existing files, so getting this wrong means no reporting.
The dead code analysis reports on globally dead values, redundant optional arguments, dead modules, dead types (records and variants).
A value x is dead if it is never used, or if it is used by a value which itself is dead (transitivity). At the top level, function calls such as print_endline x, or other expressions that might cause side effects, keep value x live.
An optional argument ?argName to a function is redundant if all the calls to the function supply the argument, or if no call does.
A module is considered dead if all the elements defined it in are dead.
The type analysis repots on variant cases, and record labels.
| A of int is dead if a value such as A 3 is never constructed. But it can be deconstructed via pattern matching | A n -> ... or checked for equality x = A 3 without making the case A live.x in type r = {x: int; y: int} is dead if it is never read (by direct access r.x or pattern matching | {x = n; y = m} -> ...). However, creating a value let r = {x = 3; y = 4} does not make x and y live. Note that reading a value r does not make r.x or r.y live.While dead values can be removed automatically (see below), dead types require a bit more work. A dead variant case requires changing the type definition, and the various accesses to it. A dead record label requires changing the type definition, and removing the label from any expressions that create a value of that type.
The dead code analysis supports 2 annotations:
[@dead] suppresses reporting on the value/type, but can also be used to force the analysis to consider a value as dead. Typically used to acknowledge cases of dead code you are not planning to address right now, but can be searched easily later.[@live] tells the analysis that the value should be considered live, even though it might appear to be dead. This is typically used in case of FFI, or other indirect ways to access values, that the analysis cannot see.The main difference between [@dead] and [@live] is the transitive behaviour: [@dead] values don't keep alive values they use, while [@live] values do.
Annotations attach to the definition, as in let[@live] x = .... Several examples can be found in examples/deadcode/src/Annotations.ml
Takes a comma-separated list of path-prefixes. Don't report on files whose path has a prefix in the list (but still use them for analysis).
reanalyze.exe -suppress one/path,another/pathTakes a comma-separated list of path-prefixes. Report on files whose path has a prefix in the list, overriding -suppress (no-op if -suppress is not specified).
reanalyze.exe -unsuppress one/path,another/path/File.mlPrint debug information during the analysis
reanalyze.exe -debug ...This overwrites your source files automatically with dead code annotations:
reanalyze.exe -write ...This automatically annotates [@live] all the items called foo or bar:
-live-names foo,barThis automatically annotates [@live] all the items in file Hello.ml:
-live-paths Hello.mlThis automatically annotates [@live] all the items in the src/test and tmp folders:
-live-paths src/test,tmpIf a native project uses code generation and emit the generated files only in the build directory, reanalyze may not be able to locate them. This is due to the paths being not relative to the project root directory. An example of it can be caused by using tools like ocamlyacc.
For example, you might want to set _build/default for projects that use the default dune build target:
-native-build-target _build/defaultopam install dune
dune build
# _build/default/src/Reanalyze.exeMake sure that dune builds both .cmt and .cmti files by enabling bytecode compilation. This is normally done by adding (modes byte exe) to the executable stanza in your dune file (see https://github.com/ocaml/dune/issues/3182):
This project is itself written in OCaml and can be analyzed as follows.
dune build
./_build/default/src/Reanalyze.exe -dce-cmt _build