Skip to content

Commit

Permalink
[4.3.5] Backport Json RPC diagnostics (#11707)
Browse files Browse the repository at this point in the history
* [display] diagnostics as json rpc (Backport #11412)

* [tests] use json rpc diagnostics

* [tests] Add test for 11695

* [tests] Update diagnostics tests

* Run some filters in diagnostics (#11220)

* let's see how much breaks

* [tests] enable diagnostics tests for 11177 and 11184

* [tests] Update test for 5306

* Don't cache/run filters for find reference/implementation requests (#11226)

* Only run filters and save cache on diagnostics, not usage requests

* [tests] Update test for 11184

* disable test

* add VUsedByTyper to avoid bad unused local errors

* revert @:compilerGenerated change

---------

Co-authored-by: Rudy Ges <k@klabz.org>

* [display] get rid of TypeloadParse.current_stdin

* [display] fix -D display-stdin handling

* [display] generalize fileContents behavior to other json rpc display calls

* [display] fix range of pattern variables

Note: not including texprConverter changes

see 160a490
see #7282

* [tests] add test for #7282

* [tests] add test for #7931

* Remove populateCacheFromDisplay config

Legacy diagnostics = false, json rpc diagnostics = true

* [std] Diagnostics request doc

* [tests] Test Json RPC diagnostics with several open files

* [diagnostics] fix multi display files (#11722)

* [diagnostics] fix json rpc diagnostics display config

* [tests] Server tests: do not fail silently when runHaxeJsonCb errors

* [tests] add more diagnostics tests

* [display] rework multiple display files handling

* clean up a bit...

* [diagnostics] handle a.b.c.hx case, even if pointless

* [diagnostics] do not skip errors during DisplayProcessing.process_display_file

* Enable display tests again...

* [tests] fix display tests

---------

Co-authored-by: Simon Krajewski <simon@haxe.org>
  • Loading branch information
kLabz and Simn authored Jul 18, 2024
1 parent 75b82f8 commit f3ebf88
Show file tree
Hide file tree
Showing 49 changed files with 677 additions and 191 deletions.
29 changes: 19 additions & 10 deletions src/compiler/compiler.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ open Globals
open Common
open CompilationContext

let run_or_diagnose ctx f arg =
let run_or_diagnose ctx f =
let com = ctx.com in
let handle_diagnostics ?(depth = 0) msg kind =
ctx.has_error <- true;
add_diagnostics_message ~depth com msg kind Error;
DisplayOutput.emit_diagnostics ctx.com
match com.report_mode with
| RMLegacyDiagnostics _ -> DisplayOutput.emit_legacy_diagnostics ctx.com
| RMDiagnostics _ -> DisplayOutput.emit_diagnostics ctx.com
| _ -> die "" __LOC__
in
if is_diagnostics com then begin try
f arg
f ()
with
| Error.Error(msg,p,depth) ->
handle_diagnostics ~depth (Error.error_msg p msg) DKCompilerMessage
Expand All @@ -20,7 +23,7 @@ let run_or_diagnose ctx f arg =
handle_diagnostics (located (Lexer.error_msg msg) p) DKParserError
end
else
f arg
f ()

let run_command ctx cmd =
let t = Timer.timer ["command";cmd] in
Expand Down Expand Up @@ -279,7 +282,7 @@ let do_type ctx tctx actx =
if com.display.dms_kind <> DMNone then DisplayTexpr.check_display_file tctx cs;
List.iter (fun cpath -> ignore(tctx.Typecore.g.Typecore.do_load_module tctx cpath null_pos)) (List.rev actx.classes);
Finalization.finalize tctx;
) ();
);
com.stage <- CTypingDone;
(* If we are trying to find references, let's syntax-explore everything we know to check for the
identifier we are interested in. We then type only those modules that contain the identifier. *)
Expand All @@ -293,23 +296,25 @@ let finalize_typing ctx tctx =
let t = Timer.timer ["finalize"] in
let com = ctx.com in
com.stage <- CFilteringStart;
let main, types, modules = run_or_diagnose ctx Finalization.generate tctx in
let main, types, modules = run_or_diagnose ctx (fun () -> Finalization.generate tctx) in
com.main <- main;
com.types <- types;
com.modules <- modules;
t()

let filter ctx tctx =
let filter ctx tctx before_destruction =
let t = Timer.timer ["filters"] in
DeprecationCheck.run ctx.com;
Filters.run ctx.com tctx ctx.com.main;
run_or_diagnose ctx (fun () -> Filters.run tctx ctx.com.main before_destruction);
t()

let compile ctx actx =
let com = ctx.com in
(* Set up display configuration *)
DisplayProcessing.process_display_configuration ctx;
let restore = disable_report_mode com in
let display_file_dot_path = DisplayProcessing.process_display_file com actx in
restore ();
(* Initialize target: This allows access to the appropriate std packages and sets the -D defines. *)
let ext = Setup.initialize_target ctx com actx in
com.config <- get_config com; (* make sure to adapt all flags changes defined after platform *)
Expand All @@ -331,8 +336,12 @@ let compile ctx actx =
end;
DisplayProcessing.handle_display_after_typing ctx tctx display_file_dot_path;
finalize_typing ctx tctx;
DisplayProcessing.handle_display_after_finalization ctx tctx display_file_dot_path;
filter ctx tctx;
if is_diagnostics com then
filter ctx tctx (fun () -> DisplayProcessing.handle_display_after_finalization ctx tctx display_file_dot_path)
else begin
DisplayProcessing.handle_display_after_finalization ctx tctx display_file_dot_path;
filter ctx tctx (fun () -> ());
end;
if ctx.has_error then raise Abort;
Generate.check_auxiliary_output com actx;
com.stage <- CGenerationStart;
Expand Down
12 changes: 11 additions & 1 deletion src/compiler/displayOutput.ml
Original file line number Diff line number Diff line change
Expand Up @@ -372,12 +372,22 @@ let handle_type_path_exception ctx p c is_import pos =
api.send_result (DisplayException.fields_to_json ctx fields kind (DisplayTypes.make_subject None pos));
end

let emit_diagnostics com =
let emit_legacy_diagnostics com =
let dctx = Diagnostics.run com in
let s = Json.string_of_json (DiagnosticsPrinter.json_of_diagnostics com dctx) in
DisplayPosition.display_position#reset;
raise (Completion s)

let emit_diagnostics com =
(match com.Common.json_out with
| None -> die "" __LOC__
| Some api ->
let dctx = Diagnostics.run com in
let diagnostics = DiagnosticsPrinter.json_of_diagnostics com dctx in
DisplayPosition.display_position#reset;
api.send_result diagnostics;
raise Abort (* not reached because send_result always raises *))

let emit_statistics tctx =
let stats = Statistics.collect_statistics tctx [SFFile (DisplayPosition.display_position#get).pfile] true in
let s = Statistics.Printer.print_statistics stats in
Expand Down
79 changes: 43 additions & 36 deletions src/compiler/displayProcessing.ml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ let handle_display_argument_old com file_pos actx =
actx.did_something <- true;
(try Memory.display_memory com with e -> prerr_endline (Printexc.get_backtrace ()));
| "diagnostics" ->
com.report_mode <- RMDiagnostics []
com.report_mode <- RMLegacyDiagnostics []
| _ ->
let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format: " ^ file_pos) in
let file = Helper.unquote file in
Expand All @@ -46,9 +46,9 @@ let handle_display_argument_old com file_pos actx =
| "module-symbols" ->
create (DMModuleSymbols None)
| "diagnostics" ->
com.report_mode <- RMDiagnostics [file_unique];
com.report_mode <- RMLegacyDiagnostics [file_unique];
let dm = create DMNone in
{dm with dms_display_file_policy = DFPAlso; dms_per_file = true; dms_populate_cache = !ServerConfig.populate_cache_from_display}
{dm with dms_display_file_policy = DFPAlso; dms_per_file = true}
| "statistics" ->
com.report_mode <- RMStatistics;
let dm = create DMNone in
Expand Down Expand Up @@ -142,48 +142,53 @@ let process_display_file com actx =
| DFPOnly when (DisplayPosition.display_position#get).pfile = file_input_marker ->
actx.classes <- [];
com.main_class <- None;
begin match !TypeloadParse.current_stdin with
| Some input ->
TypeloadParse.current_stdin := None;
begin match com.file_contents with
| [_, Some input] ->
com.file_contents <- [];
DPKInput input
| None ->
| _ ->
DPKNone
end
| dfp ->
if dfp = DFPOnly then begin
actx.classes <- [];
com.main_class <- None;
end;
let real = Path.get_real_path (DisplayPosition.display_position#get).pfile in
let path = match get_module_path_from_file_path com real with
| Some path ->
if com.display.dms_kind = DMPackage then DisplayException.raise_package (fst path);
let path = match ExtString.String.nsplit (snd path) "." with
| [name;"macro"] ->
(* If we have a .macro.hx path, don't add the file to classes because the compiler won't find it.
This can happen if we're completing in such a file. *)
DPKMacro (fst path,name)
| [name] ->
actx.classes <- path :: actx.classes;
DPKNormal path
| [name;target] ->
let path = fst path, name in
actx.classes <- path :: actx.classes;
DPKNormal path
| e ->
die "" __LOC__
let dpk = List.map (fun file_key ->
let real = Path.get_real_path (Path.UniqueKey.to_string file_key) in
let dpk = match get_module_path_from_file_path com real with
| Some path ->
if com.display.dms_kind = DMPackage then DisplayException.raise_package (fst path);
let dpk = match ExtString.String.nsplit (snd path) "." with
| [name;"macro"] ->
(* If we have a .macro.hx path, don't add the file to classes because the compiler won't find it.
This can happen if we're completing in such a file. *)
DPKMacro (fst path,name)
| [name] ->
actx.classes <- path :: actx.classes;
DPKNormal path
| [name;target] ->
let path = fst path, name in
actx.classes <- path :: actx.classes;
DPKNormal path
| _ ->
failwith ("Invalid display file '" ^ real ^ "'")
in
dpk
| None ->
if not (Sys.file_exists real) then failwith "Display file does not exist";
(match List.rev (ExtString.String.nsplit real Path.path_sep) with
| file :: _ when file.[0] >= 'a' && file.[0] <= 'z' -> failwith ("Display file '" ^ file ^ "' should not start with a lowercase letter")
| _ -> ());
DPKDirect real
in
path
| None ->
if not (Sys.file_exists real) then failwith "Display file does not exist";
(match List.rev (ExtString.String.nsplit real Path.path_sep) with
| file :: _ when file.[0] >= 'a' && file.[0] <= 'z' -> failwith ("Display file '" ^ file ^ "' should not start with a lowercase letter")
| _ -> ());
DPKDirect real
in
Common.log com ("Display file : " ^ real);
Common.log com ("Display file : " ^ real);
dpk
) DisplayPosition.display_position#get_files in
Common.log com ("Classes found : [" ^ (String.concat "," (List.map s_type_path actx.classes)) ^ "]");
path
match dpk with
| [dfile] -> dfile
| _ -> DPKNone

(* 3. Loaders for display file that might be called *)

Expand Down Expand Up @@ -348,10 +353,12 @@ let handle_display_after_finalization ctx tctx display_file_dot_path =
end;
process_global_display_mode com tctx;
begin match com.report_mode with
| RMLegacyDiagnostics _ ->
DisplayOutput.emit_legacy_diagnostics com
| RMDiagnostics _ ->
DisplayOutput.emit_diagnostics com
| RMStatistics ->
DisplayOutput.emit_statistics tctx
| RMNone ->
()
end
end
23 changes: 13 additions & 10 deletions src/compiler/server.ml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,7 @@ let has_error ctx =
ctx.has_error || ctx.com.Common.has_error

let check_display_flush ctx f_otherwise = match ctx.com.json_out with
| None ->
if is_diagnostics ctx.com then begin
List.iter (fun cm ->
add_diagnostics_message ~depth:cm.cm_depth ctx.com (located cm.cm_message cm.cm_pos) cm.cm_kind cm.cm_severity
) (List.rev ctx.messages);
raise (Completion (Diagnostics.print ctx.com))
end else
f_otherwise ()
| Some api ->
| Some api when not (is_diagnostics ctx.com) ->
if has_error ctx then begin
let errors = List.map (fun cm ->
JObject [
Expand All @@ -37,6 +29,17 @@ let check_display_flush ctx f_otherwise = match ctx.com.json_out with
) (List.rev ctx.messages) in
api.send_error errors
end
| _ ->
if is_diagnostics ctx.com then begin
List.iter (fun cm ->
add_diagnostics_message ~depth:cm.cm_depth ctx.com (located cm.cm_message cm.cm_pos) cm.cm_kind cm.cm_severity
) (List.rev ctx.messages);
(match ctx.com.report_mode with
| RMDiagnostics _ -> ()
| RMLegacyDiagnostics _ -> raise (Completion (Diagnostics.print ctx.com))
| _ -> die "" __LOC__)
end else
f_otherwise ()

let current_stdin = ref None

Expand All @@ -46,7 +49,7 @@ let parse_file cs com file p =
and fkey = com.file_keys#get file in
let is_display_file = DisplayPosition.display_position#is_in_file (com.file_keys#get ffile) in
match is_display_file, !current_stdin with
| true, Some stdin when Common.defined com Define.DisplayStdin ->
| true, Some stdin when (com.file_contents <> [] || Common.defined com Define.DisplayStdin) ->
TypeloadParse.parse_file_from_string com file p stdin
| _ ->
let ftime = file_time ffile in
Expand Down
1 change: 0 additions & 1 deletion src/compiler/serverConfig.ml
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
let do_not_check_modules = ref false
let populate_cache_from_display = ref true
let legacy_completion = ref false
7 changes: 5 additions & 2 deletions src/context/common.ml
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,8 @@ type compiler_stage =

type report_mode =
| RMNone
| RMDiagnostics of Path.UniqueKey.t list
| RMLegacyDiagnostics of (Path.UniqueKey.t list)
| RMDiagnostics of (Path.UniqueKey.t list)
| RMStatistics

class virtual ['key,'value] lookup = object(self)
Expand Down Expand Up @@ -382,6 +383,7 @@ type context = {
display_information : display_information;
file_lookup_cache : (string,string option) lookup;
file_keys : file_keys;
mutable file_contents : (Path.UniqueKey.t * string option) list;
readdir_cache : (string * string,(string array) option) lookup;
parser_cache : (string,(type_def * pos) list) lookup;
module_to_file : (path,string) lookup;
Expand Down Expand Up @@ -852,6 +854,7 @@ let create compilation_step cs version args =
};
file_lookup_cache = new hashtbl_lookup;
file_keys = new file_keys;
file_contents = [];
readdir_cache = new hashtbl_lookup;
module_to_file = new hashtbl_lookup;
stored_typed_exprs = new hashtbl_lookup;
Expand All @@ -867,7 +870,7 @@ let create compilation_step cs version args =
com

let is_diagnostics com = match com.report_mode with
| RMDiagnostics _ -> true
| RMLegacyDiagnostics _ | RMDiagnostics _ -> true
| _ -> false

let disable_report_mode com =
Expand Down
18 changes: 7 additions & 11 deletions src/context/display/diagnostics.ml
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ let find_unused_variables com e =
let vars = Hashtbl.create 0 in
let pmin_map = Hashtbl.create 0 in
let rec loop e = match e.eexpr with
| TVar({v_kind = VUser _} as v,eo) when v.v_name <> "_" ->
| TVar({v_kind = VUser origin} as v,eo) when v.v_name <> "_" && not (has_var_flag v VUsedByTyper) ->
Hashtbl.add pmin_map e.epos.pmin v;
let p = match eo with
| None -> e.epos
| Some e1 ->
loop e1;
{ e.epos with pmax = e1.epos.pmin }
| Some e1 when origin <> TVOPatternVariable ->
loop e1;
{ e.epos with pmax = e1.epos.pmin }
| _ ->
e.epos
in
Hashtbl.replace vars v.v_id (v,p);
| TLocal ({v_kind = VUser _} as v) ->
Expand Down Expand Up @@ -179,15 +180,10 @@ let prepare com =
dctx.unresolved_identifiers <- com.display_information.unresolved_identifiers;
dctx

let secure_generated_code ctx e =
(* This causes problems and sucks in general... need a different solution. But I forgot which problem this solved anyway. *)
(* mk (TMeta((Meta.Extern,[],e.epos),e)) e.etype e.epos *)
e

let print com =
let dctx = prepare com in
Json.string_of_json (DiagnosticsPrinter.json_of_diagnostics com dctx)

let run com =
let dctx = prepare com in
dctx
dctx
4 changes: 2 additions & 2 deletions src/context/display/diagnosticsPrinter.ml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ let make_diagnostic kd p sev args = {

let is_diagnostics_file com file_key =
match com.report_mode with
| RMDiagnostics [] -> true
| RMDiagnostics file_keys -> List.exists (fun key' -> file_key = key') file_keys
| RMLegacyDiagnostics [] | RMDiagnostics [] -> true
| RMLegacyDiagnostics file_keys | RMDiagnostics file_keys -> List.mem file_key file_keys
| _ -> false

module UnresolvedIdentifierSuggestion = struct
Expand Down
Loading

0 comments on commit f3ebf88

Please sign in to comment.