Blame src/findlib/fl_lint.ml

Packit b513ef
(* $Id$ -*- tuareg -*-
Packit b513ef
 * ----------------------------------------------------------------------
Packit b513ef
 *
Packit b513ef
 *)
Packit b513ef
Packit b513ef
open Fl_metascanner
Packit b513ef
Packit b513ef
module Have = struct
Packit b513ef
  module T = struct
Packit b513ef
    type mode = [`Byte | `Native | `Toploop | `Preprocessor | `Ppx_driver]
Packit b513ef
    type t = [
Packit b513ef
        `Mode of [ `TooMany | `None]
Packit b513ef
      (** problem in the number of mode (byte,native,syntax,...)
Packit b513ef
          in the variable  *)
Packit b513ef
      | `Archive of [`Plugin|`NoPlugin] * mode
Packit b513ef
        (** archive(plugin,...) or archive(...)) *)
Packit b513ef
      | `Plugin of [`Plugin|`NoPlugin] * mode
Packit b513ef
        (** plugin(...) *)
Packit b513ef
      | `Description
Packit b513ef
      | `Requires
Packit b513ef
      | `Version
Packit b513ef
    ]
Packit b513ef
    let compare = compare
Packit b513ef
  end
Packit b513ef
  include T
Packit b513ef
  module Set = Set.Make(T)
Packit b513ef
  module Map = Map.Make(T)
Packit b513ef
end
Packit b513ef
Packit b513ef
let scan_def acc def =
Packit b513ef
  let add have = Have.Map.add have def acc in
Packit b513ef
  let has_plugin_pred = List.mem (`Pred "plugin") def.def_preds in
Packit b513ef
  let plugin = if has_plugin_pred then `Plugin else `NoPlugin in
Packit b513ef
  let modes = [ "byte", `Byte;
Packit b513ef
                "native", `Native;
Packit b513ef
                "toploop", `Toploop;
Packit b513ef
                "preprocessor", `Preprocessor;
Packit b513ef
                "ppx_driver", `Ppx_driver
Packit b513ef
              ] in
Packit b513ef
  let modes =
Packit b513ef
    List.filter
Packit b513ef
      (fun (p,_) -> List.mem (`Pred p) def.def_preds)
Packit b513ef
      modes
Packit b513ef
  in
Packit b513ef
  let modes = List.map snd modes in
Packit b513ef
  match def.def_var, modes with
Packit b513ef
  (** For archive the modes are used in multiple ways, so we can't
Packit b513ef
      check exhaustiveness or presence.
Packit b513ef
  *)
Packit b513ef
  | "plugin", [] -> add (`Mode(`None))
Packit b513ef
  | "plugin", _::_::_ -> add (`Mode(`TooMany))
Packit b513ef
Packit b513ef
  | "archive", [mode] -> add (`Archive(plugin,mode))
Packit b513ef
  | "plugin", [mode]  -> add (`Plugin(plugin,mode))
Packit b513ef
  | "description", _ -> add `Description
Packit b513ef
  | "requires", _ -> add `Requires
Packit b513ef
  | "version", _ -> add `Version
Packit b513ef
  | _ -> acc
Packit b513ef
Packit b513ef
Packit b513ef
let warn_def ~warned pkg =
Packit b513ef
  let haves =
Packit b513ef
    List.fold_left scan_def Have.Map.empty pkg.pkg_defs
Packit b513ef
  in
Packit b513ef
  let mem x  = Have.Map.mem x haves in
Packit b513ef
  let find x = Have.Map.find x haves in
Packit b513ef
  let warning fmt = warned := true; Printf.printf fmt in
Packit b513ef
  let if_ ?has ?(has_not=[]) msg =
Packit b513ef
    match has, has_not with
Packit b513ef
    | Some has, [] when mem has ->
Packit b513ef
      warning "%a%s\n\n" print_def (find has) msg;
Packit b513ef
    | Some has, has_not when mem has && not (List.exists mem has_not) ->
Packit b513ef
      warning "%a%s\n\n" print_def (find has) msg;
Packit b513ef
    | None, has_not when not (List.exists mem has_not) ->
Packit b513ef
      warning "%s\n\n" msg;
Packit b513ef
    | _ -> ()
Packit b513ef
  in
Packit b513ef
  if_ ~has_not:[`Description]
Packit b513ef
    "You should add a description.";
Packit b513ef
  if_ ~has_not:[`Version]
Packit b513ef
    "You should add a version.";
Packit b513ef
  if_ ~has_not:[`Requires]
Packit b513ef
    "You should add the required libraries. You can silent this \
Packit b513ef
     warning by using the empty string.";
Packit b513ef
  if_ ~has:(`Mode(`TooMany))
Packit b513ef
    "This variable should have only one mode
Packit b513ef
     (\"byte\", \"native\").";
Packit b513ef
  if_ ~has:(`Mode(`None))
Packit b513ef
    "This variable should have at least the predicate \
Packit b513ef
     \"byte\" or \"native\".";
Packit b513ef
  let with_mode mode =
Packit b513ef
    if_ ~has:(`Plugin (`Plugin,mode))
Packit b513ef
      "You must not add the predicate \"plugin\" to the variable \
Packit b513ef
       \"plugin\".";
Packit b513ef
    if_ ~has:(`Archive (`Plugin,mode)) ~has_not:[`Plugin (`NoPlugin,mode)]
Packit b513ef
      "This specification of dynamic loading is deprecated, you should add a \
Packit b513ef
       \"plugin(...)\" variable.";
Packit b513ef
    if_ ~has:(`Archive (`NoPlugin,mode))
Packit b513ef
      ~has_not:[`Plugin (`NoPlugin,mode);`Archive (`Plugin,mode)]
Packit b513ef
      "This variable indicates how to link statically, you should add a \
Packit b513ef
       \"plugin(...)\" variable for linking dynamically.";
Packit b513ef
  in
Packit b513ef
  with_mode `Byte;
Packit b513ef
  with_mode `Native
Packit b513ef
Packit b513ef
let warn pkg =
Packit b513ef
  let warned = ref false in
Packit b513ef
  let rec aux pkg =
Packit b513ef
    warn_def ~warned pkg;
Packit b513ef
    List.iter (fun (_,pkg) -> aux pkg) pkg.pkg_children;
Packit b513ef
  in
Packit b513ef
  aux pkg;
Packit b513ef
  !warned