|
@@ -7,7 +7,21 @@ open Type
|
|
open Genjson
|
|
open Genjson
|
|
open MessageKind
|
|
open MessageKind
|
|
|
|
|
|
-(* type t = DiagnosticsKind.t * pos *)
|
|
|
|
|
|
+type t = {
|
|
|
|
+ diag_kind : MessageKind.t;
|
|
|
|
+ diag_pos : pos;
|
|
|
|
+ diag_severity : MessageSeverity.t;
|
|
|
|
+ diag_args : Json.t;
|
|
|
|
+ mutable diag_related_information : (pos * int * string) list;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+let make_diagnostic kd p sev args = {
|
|
|
|
+ diag_kind = kd;
|
|
|
|
+ diag_pos = p;
|
|
|
|
+ diag_severity = sev;
|
|
|
|
+ diag_args = args;
|
|
|
|
+ diag_related_information = [];
|
|
|
|
+}
|
|
|
|
|
|
let is_diagnostics_file com file_key =
|
|
let is_diagnostics_file com file_key =
|
|
match com.report_mode with
|
|
match com.report_mode with
|
|
@@ -30,18 +44,20 @@ open CompletionItem
|
|
open CompletionModuleType
|
|
open CompletionModuleType
|
|
|
|
|
|
let json_of_diagnostics com dctx =
|
|
let json_of_diagnostics com dctx =
|
|
- let diag = Hashtbl.create 0 in
|
|
|
|
- let add append dk p sev args =
|
|
|
|
|
|
+ let diagnostics = Hashtbl.create 0 in
|
|
|
|
+ let current = ref None in
|
|
|
|
+ let add append diag =
|
|
|
|
+ let p = diag.diag_pos in
|
|
let file = if p = null_pos then p.pfile else Path.get_real_path p.pfile in
|
|
let file = if p = null_pos then p.pfile else Path.get_real_path p.pfile in
|
|
- let diag = try
|
|
|
|
- Hashtbl.find diag file
|
|
|
|
|
|
+ let fdiag = try
|
|
|
|
+ Hashtbl.find diagnostics file
|
|
with Not_found ->
|
|
with Not_found ->
|
|
- let d = Hashtbl.create 0 in
|
|
|
|
- Hashtbl.add diag file d;
|
|
|
|
|
|
+ let d = [] in
|
|
|
|
+ Hashtbl.add diagnostics file d;
|
|
d
|
|
d
|
|
in
|
|
in
|
|
- if append || not (Hashtbl.mem diag p) then
|
|
|
|
- Hashtbl.add diag p (dk,p,sev,args)
|
|
|
|
|
|
+ if append || (List.find_opt (fun diag -> diag.diag_pos = p) fdiag) = None then
|
|
|
|
+ Hashtbl.replace diagnostics file (diag :: fdiag)
|
|
in
|
|
in
|
|
let file_keys = new Common.file_keys in
|
|
let file_keys = new Common.file_keys in
|
|
let add dk p sev args =
|
|
let add dk p sev args =
|
|
@@ -57,7 +73,11 @@ let json_of_diagnostics com dctx =
|
|
| DKMissingFields ->
|
|
| DKMissingFields ->
|
|
true
|
|
true
|
|
in
|
|
in
|
|
- if p = null_pos || is_diagnostics_file com (file_keys#get p.pfile) then add append dk p sev args
|
|
|
|
|
|
+ if p = null_pos || is_diagnostics_file com (file_keys#get p.pfile) then begin
|
|
|
|
+ let diag = make_diagnostic dk p sev args in
|
|
|
|
+ current := Some diag;
|
|
|
|
+ add append diag
|
|
|
|
+ end else current := None
|
|
in
|
|
in
|
|
List.iter (fun (s,p,suggestions) ->
|
|
List.iter (fun (s,p,suggestions) ->
|
|
let suggestions = ExtList.List.filter_map (fun (s,item,r) ->
|
|
let suggestions = ExtList.List.filter_map (fun (s,item,r) ->
|
|
@@ -79,8 +99,22 @@ let json_of_diagnostics com dctx =
|
|
) suggestions in
|
|
) suggestions in
|
|
add DKUnresolvedIdentifier p MessageSeverity.Error (JArray suggestions);
|
|
add DKUnresolvedIdentifier p MessageSeverity.Error (JArray suggestions);
|
|
) dctx.unresolved_identifiers;
|
|
) dctx.unresolved_identifiers;
|
|
- List.iter (fun (s,p,kind,sev) ->
|
|
|
|
- add kind p sev (JString s)
|
|
|
|
|
|
+ List.iter (fun (s,p,kind,sev,depth) -> match (depth, !current) with
|
|
|
|
+ | d, Some diag when d > 0 ->
|
|
|
|
+ let lines = ExtString.String.nsplit s "\n" in
|
|
|
|
+ (match lines with
|
|
|
|
+ | [] -> ()
|
|
|
|
+ | s :: sub ->
|
|
|
|
+ let related = List.fold_left (fun acc s -> (p,d,Error.compl_msg s) :: acc) diag.diag_related_information sub in
|
|
|
|
+ diag.diag_related_information <- (p,d,s) :: related;
|
|
|
|
+ )
|
|
|
|
+ | 0, _ ->
|
|
|
|
+ add kind p sev (JString s)
|
|
|
|
+ | _ ->
|
|
|
|
+ (* Do not add errors with depth greater than one as top level diagnostic. *)
|
|
|
|
+ (* This could happen when running diagnostics for a file that is wentioned in *)
|
|
|
|
+ (* sub errors of a file not included for diagnostics. *)
|
|
|
|
+ ()
|
|
) (List.rev dctx.diagnostics_messages);
|
|
) (List.rev dctx.diagnostics_messages);
|
|
PMap.iter (fun p (mt,mfl) ->
|
|
PMap.iter (fun p (mt,mfl) ->
|
|
let jctx = create_context GMMinimum in
|
|
let jctx = create_context GMMinimum in
|
|
@@ -171,18 +205,25 @@ let json_of_diagnostics com dctx =
|
|
) ranges
|
|
) ranges
|
|
) dctx.dead_blocks;
|
|
) dctx.dead_blocks;
|
|
let jl = Hashtbl.fold (fun file diag acc ->
|
|
let jl = Hashtbl.fold (fun file diag acc ->
|
|
- let jl = Hashtbl.fold (fun _ (dk,p,sev,jargs) acc ->
|
|
|
|
|
|
+ let jl = List.rev_map (fun diag ->
|
|
(JObject [
|
|
(JObject [
|
|
- "kind",JInt (MessageKind.to_int dk);
|
|
|
|
- "severity",JInt (MessageSeverity.to_int sev);
|
|
|
|
- "range",Genjson.generate_pos_as_range p;
|
|
|
|
- "args",jargs
|
|
|
|
- ]) :: acc
|
|
|
|
- ) diag [] in
|
|
|
|
|
|
+ "kind",JInt (MessageKind.to_int diag.diag_kind);
|
|
|
|
+ "severity",JInt (MessageSeverity.to_int diag.diag_severity);
|
|
|
|
+ "range",Genjson.generate_pos_as_range diag.diag_pos;
|
|
|
|
+ "args",diag.diag_args;
|
|
|
|
+ "relatedInformation",JArray (
|
|
|
|
+ List.rev_map (fun (pos,depth,msg) -> (JObject [
|
|
|
|
+ "location",Genjson.generate_pos_as_location pos;
|
|
|
|
+ "depth",JInt depth;
|
|
|
|
+ "message",JString msg;
|
|
|
|
+ ])) diag.diag_related_information
|
|
|
|
+ )
|
|
|
|
+ ])
|
|
|
|
+ ) diag in
|
|
(JObject [
|
|
(JObject [
|
|
"file",if file = "?" then JNull else JString file;
|
|
"file",if file = "?" then JNull else JString file;
|
|
"diagnostics",JArray jl
|
|
"diagnostics",JArray jl
|
|
]) :: acc
|
|
]) :: acc
|
|
- ) diag [] in
|
|
|
|
|
|
+ ) diagnostics [] in
|
|
let js = JArray jl in
|
|
let js = JArray jl in
|
|
- js
|
|
|
|
|
|
+ js
|