|
@@ -12,7 +12,7 @@ let filter_report : Args.filters -> Report.t list -> Report.t -> Report.t list =
|
|
|
|
|
|
match is_ok with true -> r :: reports | _ -> reports
|
|
|
|
|
|
-type ctx = { error_nb : int; warn_nb : int; debug_nb : int }
|
|
|
+type ctx = { error_nb : int; warn_nb : int; debug_nb : int; fatal_error : bool }
|
|
|
|
|
|
(*
|
|
|
List all the controls to apply
|
|
@@ -22,6 +22,7 @@ let available_checks =
|
|
|
snd @@ Qsp_syntax.Check.build (module Qsp_syntax.Type_of);
|
|
|
snd @@ Qsp_syntax.Check.build (module Qsp_syntax.Dead_end);
|
|
|
snd @@ Qsp_syntax.Check.build (module Qsp_syntax.Nested_strings);
|
|
|
+ snd @@ Qsp_syntax.Check.build (module Qsp_syntax.Locations);
|
|
|
]
|
|
|
|
|
|
let pp_module formatter (module A : Qsp_syntax.S.Analyzer) =
|
|
@@ -83,39 +84,44 @@ let checkers : (module Qsp_syntax.S.Analyzer) Lazy.t =
|
|
|
(module Check))
|
|
|
|
|
|
(** Read the source file until getting a report (the whole location has been
|
|
|
- read properly), or until the first syntax error.
|
|
|
- *)
|
|
|
-let parse_location : ctx:ctx -> Qparser.Lexbuf.t -> Args.filters -> ctx =
|
|
|
- fun ~ctx lexbuf filters ->
|
|
|
- let (module Check) = Lazy.force checkers in
|
|
|
+ read properly), or until the first syntax error.
|
|
|
+
|
|
|
+ The function update the context (list of errors) passed in arguments. *)
|
|
|
+let parse_location :
|
|
|
+ type context.
|
|
|
+ ctx:ctx ref ->
|
|
|
+ (module Qsp_syntax.S.Analyzer with type context = context) ->
|
|
|
+ context ->
|
|
|
+ Qparser.Lexbuf.t ->
|
|
|
+ Args.filters ->
|
|
|
+ unit =
|
|
|
+ fun ~ctx (module Check) context lexbuf filters ->
|
|
|
let result =
|
|
|
- Qparser.Analyzer.parse (module Check) lexbuf
|
|
|
- |> Result.map (fun (_, f) ->
|
|
|
- List.fold_left f ~init:[] ~f:(filter_report filters)
|
|
|
+ Qparser.Analyzer.parse (module Check) lexbuf context
|
|
|
+ |> Result.map (fun f ->
|
|
|
+ List.fold_left f.Qparser.Analyzer.report ~init:[]
|
|
|
+ ~f:(filter_report filters)
|
|
|
|> List.sort ~cmp:Report.compare)
|
|
|
in
|
|
|
match result with
|
|
|
- | Ok report -> (
|
|
|
+ | Ok [] -> ()
|
|
|
+ | Ok report ->
|
|
|
(* Display the result *)
|
|
|
- match report with
|
|
|
- | [] -> ctx
|
|
|
- | _ ->
|
|
|
- let start_position, _ = Qparser.Lexbuf.positions lexbuf in
|
|
|
- Format.fprintf Format.std_formatter "Location@ %s@;@[%a@]@."
|
|
|
- start_position.Lexing.pos_fname Report.pp_result report;
|
|
|
-
|
|
|
- List.fold_left report ~init:ctx ~f:(fun ctx report ->
|
|
|
- match report.Report.level with
|
|
|
- | Error -> { ctx with error_nb = succ ctx.error_nb }
|
|
|
- | Warn -> { ctx with warn_nb = succ ctx.warn_nb }
|
|
|
- | Debug -> { ctx with debug_nb = succ ctx.debug_nb }))
|
|
|
+ let start_position, _ = Qparser.Lexbuf.positions lexbuf in
|
|
|
+ Format.fprintf Format.std_formatter "Location@ %s@;@[%a@]@."
|
|
|
+ start_position.Lexing.pos_fname Report.pp_result report;
|
|
|
+
|
|
|
+ List.iter report ~f:(fun report ->
|
|
|
+ match report.Report.level with
|
|
|
+ | Error -> ctx := { !ctx with error_nb = succ !ctx.error_nb }
|
|
|
+ | Warn -> ctx := { !ctx with warn_nb = succ !ctx.warn_nb }
|
|
|
+ | Debug -> ctx := { !ctx with debug_nb = succ !ctx.debug_nb })
|
|
|
| Error e ->
|
|
|
+ (* Syntax error, we haven’t been able to run the test *)
|
|
|
let start_position, _ = Qparser.Lexbuf.positions lexbuf in
|
|
|
Format.fprintf Format.std_formatter "Location@ %s@;@[%a]@."
|
|
|
start_position.Lexing.pos_fname Report.pp e;
|
|
|
- { ctx with error_nb = succ ctx.error_nb }
|
|
|
-
|
|
|
-let default_ctx = { error_nb = 0; warn_nb = 0; debug_nb = 0 }
|
|
|
+ ctx := { !ctx with error_nb = succ !ctx.error_nb; fatal_error = true }
|
|
|
|
|
|
let () =
|
|
|
let file_names, parameters =
|
|
@@ -129,6 +135,12 @@ let () =
|
|
|
let lexer, parameters =
|
|
|
match Filename.extension file_name with
|
|
|
| ".qsrc" ->
|
|
|
+ (* Deactivate the tests which only applies to a global file *)
|
|
|
+ List.iter available_checks ~f:(fun t ->
|
|
|
+ let (module C : Qsp_syntax.S.Analyzer) =
|
|
|
+ Qsp_syntax.Check.get_module t
|
|
|
+ in
|
|
|
+ if C.is_global then C.active := false);
|
|
|
(* The source file are in UTF-8, and we can use the file line number as
|
|
|
we have only a single location. *)
|
|
|
( Sedlexing.Utf8.from_channel ic,
|
|
@@ -142,15 +154,40 @@ let () =
|
|
|
Qparser.Lexbuf.from_lexbuf ~reset_line:parameters.reset_line lexer
|
|
|
in
|
|
|
|
|
|
- let ctx = ref default_ctx in
|
|
|
+ (* Initialize all the checkers before parsing the source *)
|
|
|
+ let (module Check) = Lazy.force checkers in
|
|
|
+ let check_context = Check.initialize () in
|
|
|
+ let ctx =
|
|
|
+ ref { error_nb = 0; warn_nb = 0; debug_nb = 0; fatal_error = false }
|
|
|
+ in
|
|
|
+
|
|
|
let () =
|
|
|
try
|
|
|
while true do
|
|
|
- ctx := parse_location ~ctx:!ctx lexer parameters.filters
|
|
|
+ parse_location ~ctx
|
|
|
+ (module Check)
|
|
|
+ check_context lexer parameters.filters
|
|
|
done
|
|
|
with Qparser.Lexer.EOF -> ()
|
|
|
in
|
|
|
|
|
|
+ (match !ctx.fatal_error with
|
|
|
+ | true ->
|
|
|
+ Format.fprintf Format.std_formatter
|
|
|
+ "(Ignoring global checkers because of the previous syntax errors)@."
|
|
|
+ | false ->
|
|
|
+ (* If the parsing was global and we didn’t got parsing error, extract the
|
|
|
+ result for the whole test *)
|
|
|
+ let global_report = Check.finalize check_context in
|
|
|
+ List.iter global_report ~f:(fun (f_name, report) ->
|
|
|
+ Format.fprintf Format.std_formatter "Location@ %s@;@[%a@]@." f_name
|
|
|
+ Report.pp report;
|
|
|
+
|
|
|
+ match report.Report.level with
|
|
|
+ | Error -> ctx := { !ctx with error_nb = succ !ctx.error_nb }
|
|
|
+ | Warn -> ctx := { !ctx with warn_nb = succ !ctx.warn_nb }
|
|
|
+ | Debug -> ctx := { !ctx with debug_nb = succ !ctx.debug_nb }));
|
|
|
+
|
|
|
match (!ctx.error_nb, !ctx.warn_nb) with
|
|
|
| 0, 0 -> (
|
|
|
print_endline "No errors found";
|