Просмотр исходного кода

Add server/resetCache and use it in the server tests (#11482)

* [server] add server/resetCache and use it in the server tests

* found it

* reset more (but it's still not enough)

* dodge segfault case to see if there are further problems

* [tests] setup: give GC some time to run when needed

* relocate fake_modules to global typer

* check if the full suite makes things worse still

* are you the culprit?

---------

Co-authored-by: Rudy Ges <[email protected]>
Simon Krajewski 1 год назад
Родитель
Сommit
c880d1decd

+ 8 - 0
src/compiler/compilationCache.ml

@@ -142,6 +142,14 @@ class cache = object(self)
 	val native_libs : (string,cached_native_lib) Hashtbl.t = Hashtbl.create 0
 	val mutable tasks : (server_task PriorityQueue.t) = PriorityQueue.Empty
 
+	method clear =
+		Hashtbl.clear contexts;
+		context_list <- [];
+		Hashtbl.clear haxelib;
+		Hashtbl.clear directories;
+		Hashtbl.clear native_libs;
+		tasks <- PriorityQueue.Empty
+
 	(* contexts *)
 
 	method get_context sign =

+ 1 - 1
src/compiler/server.ml

@@ -301,7 +301,7 @@ let check_module sctx com m_path m_extra p =
 					ServerMessage.unchanged_content com "" file;
 				end else begin
 					ServerMessage.not_cached com "" m_path;
-					if m_extra.m_kind = MFake then Hashtbl.remove fake_modules (Path.UniqueKey.lazy_key m_extra.m_file);
+					if m_extra.m_kind = MFake then Hashtbl.remove com.fake_modules (Path.UniqueKey.lazy_key m_extra.m_file);
 					raise (Dirty (FileChanged file))
 				end
 			end

+ 1 - 0
src/compiler/serverCompilationContext.ml

@@ -45,6 +45,7 @@ let reset sctx =
 	Hashtbl.clear sctx.changed_directories;
 	sctx.was_compilation <- false;
 	Parser.reset_state();
+	Lexer.cur := Lexer.make_file "";
 	measure_times := false;
 	Hashtbl.clear DeprecationCheck.warned_positions;
 	close_times();

+ 8 - 0
src/compiler/serverConfig.ml

@@ -1,3 +1,11 @@
 let do_not_check_modules = ref false
 let populate_cache_from_display = ref true
 let legacy_completion = ref false
+
+let max_completion_items = ref 0
+
+let reset () =
+	do_not_check_modules := false;
+	populate_cache_from_display := true;
+	legacy_completion := false;
+	max_completion_items := 0

+ 3 - 0
src/context/common.ml

@@ -398,6 +398,7 @@ type context = {
 	overload_cache : ((path * string),(Type.t * tclass_field) list) lookup;
 	module_lut : module_lut;
 	module_nonexistent_lut : (path,bool) lookup;
+	fake_modules : (Path.UniqueKey.t,module_def) Hashtbl.t;
 	mutable has_error : bool;
 	pass_debug_messages : string DynArray.t;
 	(* output *)
@@ -833,6 +834,7 @@ let create compilation_step cs version args display_mode =
 		modules = [];
 		module_lut = new module_lut;
 		module_nonexistent_lut = new hashtbl_lookup;
+		fake_modules = Hashtbl.create 0;
 		flash_version = 10.;
 		resources = Hashtbl.create 0;
 		net_std = [];
@@ -932,6 +934,7 @@ let clone com is_macro_context =
 		module_to_file = new hashtbl_lookup;
 		overload_cache = new hashtbl_lookup;
 		module_lut = new module_lut;
+		fake_modules = Hashtbl.create 0;
 		hxb_reader_stats = HxbReader.create_hxb_reader_stats ();
 		std = null_class;
 		empty_class_path = new ClassPath.directory_class_path "" User;

+ 7 - 4
src/context/display/displayException.ml

@@ -18,7 +18,10 @@ let raise_package sl = raise (DisplayException(DisplayPackage sl))
 (* global state *)
 let last_completion_result = ref (Array.make 0 (CompletionItem.make (ITModule ([],"")) None))
 let last_completion_pos = ref None
-let max_completion_items = ref 0
+
+let reset () =
+	last_completion_result := (Array.make 0 (CompletionItem.make (ITModule ([],"")) None));
+	last_completion_pos := None
 
 let filter_somehow ctx items kind subj =
 	let subject = match subj.s_name with
@@ -88,7 +91,7 @@ let filter_somehow ctx items kind subj =
 	in
 	let ret = DynArray.create () in
 	let rec loop acc_types = match acc_types with
-		| (item,index,_) :: acc_types when DynArray.length ret < !max_completion_items ->
+		| (item,index,_) :: acc_types when DynArray.length ret < !ServerConfig.max_completion_items ->
 			DynArray.add ret (CompletionItem.to_json ctx (Some index) item);
 			loop acc_types
 		| _ ->
@@ -113,7 +116,7 @@ let patch_completion_subject subj =
 
 let fields_to_json ctx fields kind subj =
 	last_completion_result := Array.of_list fields;
-	let needs_filtering = !max_completion_items > 0 && Array.length !last_completion_result > !max_completion_items in
+	let needs_filtering = !ServerConfig.max_completion_items > 0 && Array.length !last_completion_result > !ServerConfig.max_completion_items in
 	(* let p_before = subj.s_insert_pos in *)
 	let subj = patch_completion_subject subj in
 	let ja,num_items = if needs_filtering then
@@ -121,7 +124,7 @@ let fields_to_json ctx fields kind subj =
 	else
 		List.mapi (fun i item -> CompletionItem.to_json ctx (Some i) item) fields,Array.length !last_completion_result
  	in
-	let did_filter = num_items = !max_completion_items in
+	let did_filter = num_items = !ServerConfig.max_completion_items in
 	last_completion_pos := if did_filter then Some subj.s_start_pos else None;
 	let filter_string = (match subj.s_name with None -> "" | Some name -> name) in
 	(* print_endline (Printf.sprintf "FIELDS OUTPUT:\n\tfilter_string: %s\n\t    num items: %i\n\t        start: %s\n\t     position: %s\n\t   before cut: %s"

+ 10 - 1
src/context/display/displayJson.ml

@@ -167,7 +167,7 @@ let handler =
 	let l = [
 		"initialize", (fun hctx ->
 			supports_resolve := hctx.jsonrpc#get_opt_param (fun () -> hctx.jsonrpc#get_bool_param "supportsResolve") false;
-			DisplayException.max_completion_items := hctx.jsonrpc#get_opt_param (fun () -> hctx.jsonrpc#get_int_param "maxCompletionItems") 0;
+			ServerConfig.max_completion_items := hctx.jsonrpc#get_opt_param (fun () -> hctx.jsonrpc#get_int_param "maxCompletionItems") 0;
 			let exclude = hctx.jsonrpc#get_opt_param (fun () -> hctx.jsonrpc#get_array_param "exclude") [] in
 			DisplayToplevel.exclude := List.map (fun e -> match e with JString s -> s | _ -> die "" __LOC__) exclude;
 			let methods = Hashtbl.fold (fun k _ acc -> (jstring k) :: acc) h [] in
@@ -310,6 +310,15 @@ let handler =
 				) all))
 			)
 		);
+		"server/resetCache", (fun hctx ->
+			hctx.com.cs#clear;
+			supports_resolve := false;
+			DisplayException.reset();
+			ServerConfig.reset();
+			hctx.send_result (jobject [
+				"success", jbool true
+			]);
+		);
 		"server/readClassPaths", (fun hctx ->
 			hctx.com.callbacks#add_after_init_macros (fun () ->
 				let cc = hctx.display#get_cs#get_context (Define.get_signature hctx.com.defines) in

+ 10 - 7
src/syntax/parser.ml

@@ -159,6 +159,12 @@ let had_resume = ref false
 let code_ref = ref (Sedlexing.Utf8.from_string "")
 let delayed_syntax_completion : (syntax_completion * DisplayTypes.completion_subject) option ref = ref None
 
+(* Per-file state *)
+
+let in_display_file = ref false
+let last_doc : (string * int) option ref = ref None
+let syntax_errors = ref []
+
 let reset_state () =
 	in_display := false;
 	was_auto_triggered := false;
@@ -167,13 +173,10 @@ let reset_state () =
 	in_macro := false;
 	had_resume := false;
 	code_ref := Sedlexing.Utf8.from_string "";
-	delayed_syntax_completion := None
-
-(* Per-file state *)
-
-let in_display_file = ref false
-let last_doc : (string * int) option ref = ref None
-let syntax_errors = ref []
+	delayed_syntax_completion := None;
+	in_display_file := false;
+	last_doc := None;
+	syntax_errors := []
 
 let syntax_error_with_pos error_msg p v =
 	let p = if p.pmax = max_int then {p with pmax = p.pmin + 1} else p in

+ 8 - 0
std/haxe/display/Protocol.hx

@@ -30,6 +30,14 @@ class Methods {
 		The initialize request is sent from the client to Haxe to determine the capabilities.
 	**/
 	static inline var Initialize = new HaxeRequestMethod<InitializeParams, InitializeResult>("initialize");
+
+	static inline var ResetCache = new HaxeRequestMethod<ResetCacheParams, ResetCacheResult>("server/resetCache");
+}
+
+typedef ResetCacheParams = {}
+
+typedef ResetCacheResult = {
+	final success:Bool;
 }
 
 /* Initialize */

+ 2 - 1
tests/server/build.hxml

@@ -6,7 +6,8 @@
 -lib utest
 -lib haxeserver
 -D analyzer-optimize
-# -D UTEST_PATTERN=9087
+-D UTEST-PRINT-TESTS
+#-D UTEST_PATTERN=ServerTests
 # or set UTEST_PATTERN environment variable
 
 #Temporary. To find out what's wrong with random CI failures

+ 11 - 2
tests/server/src/Main.hx

@@ -1,6 +1,8 @@
 import utest.ui.Report;
 import utest.Runner;
 import utils.Vfs;
+import haxeserver.HaxeServerAsync;
+import haxeserver.process.HaxeServerProcessNode;
 
 class Main {
 	static public function main() {
@@ -11,6 +13,13 @@ class Main {
 		var report = Report.create(runner);
 		report.displayHeader = AlwaysShowHeader;
 		report.displaySuccessResults = NeverShowSuccessResults;
-		runner.run();
+		var cwd = Sys.getCwd();
+		var server:HaxeServerAsync = null;
+		runner.onComplete.add(_ -> server.stop());
+		server = new HaxeServerAsync(() -> new HaxeServerProcessNode("haxe", ["-v"], {}, () -> {
+			TestCase.server = server;
+			TestCase.rootCwd = cwd;
+			runner.run();
+		}));
 	}
-}
+}

+ 8 - 5
tests/server/src/TestCase.hx

@@ -26,7 +26,9 @@ class TestCase implements ITest {
 		prints:Array<String>
 	};
 
-	var server:HaxeServerAsync;
+	static public var server:HaxeServerAsync;
+	static public var rootCwd:String;
+
 	var vfs:Vfs;
 	var testDir:String;
 	var lastResult:HaxeServerRequestResult;
@@ -69,15 +71,16 @@ class TestCase implements ITest {
 		}
 	}
 
+	@:timeout(3000)
 	public function setup(async:utest.Async) {
 		testDir = "test/cases/" + i++;
 		vfs = new Vfs(testDir);
-		server = new HaxeServerAsync(() -> new HaxeServerProcessNode("haxe", ["-v", "--cwd", testDir], {}, () -> async.done()));
+		runHaxeJson(["--cwd", rootCwd, "--cwd", testDir], Methods.ResetCache, {}, () -> {
+			async.done();
+		});
 	}
 
-	public function teardown() {
-		server.stop();
-	}
+	public function teardown() {}
 
 	function handleResult(result) {
 		lastResult = result;

+ 0 - 21
tests/server/src/cases/issues/Issue10646.hx

@@ -1,21 +0,0 @@
-package cases.issues;
-
-class Issue10646 extends TestCase {
-	function test(_) {
-		vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
-		var args = ["-main", "HelloWorld", "--neko", "test.n"];
-		runHaxe(args);
-		var nekoCtx = null;
-		runHaxeJsonCb([], ServerMethods.Contexts, null, function(ctxs) {
-			for (ctx in ctxs) {
-				if (ctx.desc == "after_init_macros") {
-					nekoCtx = ctx;
-				}
-			}
-		});
-		Assert.notNull(nekoCtx);
-		runHaxeJsonCb([], ServerMethods.ContextMemory, {signature: nekoCtx.signature}, function(mem) {
-			Assert.isNull(mem.leaks);
-		});
-	}
-}