The exception analysis is designed to keep track statically of the exceptions that might be raised at runtime. It works by issuing warnings and recognizing annotations. Warnings are issued whenever an exception is raised and not immediately caught. Annotations are used to push warnings from he local point where the exception is raised, to the outside context: callers of the current function. Nested functions need to be annotated separately.
Instructions on how to run the exception analysis using the -exception-cmt command-line argument are contained in the general README.md.
Here's an example, where the analysis reports a warning any time an exception is raised, and not caught:
let raises () = raise Not_foundreports:
Exception Analysis
File "A.ml", line 1, characters 4-10
raises might raise Not_found (A.ml:1:16) and is not annotated with @raises(Not_found)No warning is reporteed when a [@raises] annotation is added:
let[@raises Not_found] raises () = raise Not_foundWhen a function raises multiple exceptions, a tuple annotation is used:
exception A
exception B
let[@raises (A, B)] twoExceptions x y =
if x then raise A;
if y then raise BIt is possible to silence the analysis by adding a [@doesNotRaise] annotaion:
let[@raises Invalid_argument] stringMake1 = String.make 12 ' '
(* Silence only the make function *)
let stringMake2 = (String.make [@doesNotRaise]) 12 ' '
(* Silence the entire call (including arguments to make) *)
let stringMake3 = (String.make 12 ' ' [@doesNotRaise])- The libraries currently modeled are limited to
Array,Buffer,Bytes,Char,Filename,Hashtbl,List,Pervasives,Str,Stringfrom the standard library, andYojson.Basic. Models are currently vendored in the analysis, and are easy to add (seesrc/ExnLib.ml) - Generic exceptions are not understood by the analysis. For example
exnis not recognized below (only concrete exceptions are):
try foo () with exn -> raise exn-
Uses of e.g.
List.hdare interpered as belonging to the standard libry. If you re-defineListin the local scope, the analysis it will think it's dealing withListfrom the standard library. -
There is no special support for functors. So with
Hashtbl.Make(...)the builtin model will not apply. So the analysis won't report that the following can raiseNot_found:
module StringHash = Hashtbl.Make (struct
include String
let hash = Hashtbl.hash
end)
let specializedHash tbl = StringHash.find tbl "abc"