浏览代码

[server] track initialization status per-signature

closes #8666
Simon Krajewski 6 年之前
父节点
当前提交
9f0489a51c

+ 1 - 0
src/compiler/server.ml

@@ -538,6 +538,7 @@ let create sctx write params =
 				ServerMessage.class_paths_changed ctx.com "";
 				ServerMessage.class_paths_changed ctx.com "";
 				Hashtbl.replace sctx.class_paths sign ctx.com.class_path;
 				Hashtbl.replace sctx.class_paths sign ctx.com.class_path;
 				CompilationServer.clear_directories cs sign;
 				CompilationServer.clear_directories cs sign;
+				CompilationServer.set_initialized cs sign false;
 			end;
 			end;
 		with Not_found ->
 		with Not_found ->
 			Hashtbl.add sctx.class_paths sign ctx.com.class_path;
 			Hashtbl.add sctx.class_paths sign ctx.com.class_path;

+ 6 - 6
src/context/compilationServer.ml

@@ -28,6 +28,7 @@ type cache = {
 	c_directories : (string, cached_directory list) Hashtbl.t;
 	c_directories : (string, cached_directory list) Hashtbl.t;
 	c_removed_files : (string * string,unit) Hashtbl.t;
 	c_removed_files : (string * string,unit) Hashtbl.t;
 	c_native_libs : (string,cached_native_lib) Hashtbl.t;
 	c_native_libs : (string,cached_native_lib) Hashtbl.t;
+	c_initialization_status : (string,bool) Hashtbl.t;
 }
 }
 
 
 type context_sign = {
 type context_sign = {
@@ -38,7 +39,6 @@ type context_sign = {
 type t = {
 type t = {
 	cache : cache;
 	cache : cache;
 	mutable signs : (string * context_sign) list;
 	mutable signs : (string * context_sign) list;
-	mutable initialized : bool;
 }
 }
 
 
 type context_options =
 type context_options =
@@ -55,13 +55,13 @@ let create_cache () = {
 	c_directories = Hashtbl.create 0;
 	c_directories = Hashtbl.create 0;
 	c_removed_files = Hashtbl.create 0;
 	c_removed_files = Hashtbl.create 0;
 	c_native_libs = Hashtbl.create 0;
 	c_native_libs = Hashtbl.create 0;
+	c_initialization_status = Hashtbl.create 0;
 }
 }
 
 
 let create () =
 let create () =
 	let cs = {
 	let cs = {
 		cache = create_cache();
 		cache = create_cache();
 		signs = [];
 		signs = [];
-		initialized = false;
 	} in
 	} in
 	instance := Some cs;
 	instance := Some cs;
 	cs
 	cs
@@ -74,11 +74,11 @@ let runs () =
 
 
 let force () = match !instance with None -> assert false | Some i -> i
 let force () = match !instance with None -> assert false | Some i -> i
 
 
-let is_initialized cs =
-	cs.initialized = true
+let is_initialized cs sign =
+	try Hashtbl.find cs.cache.c_initialization_status sign with Not_found -> false
 
 
-let set_initialized cs =
-	cs.initialized <- true
+let set_initialized cs sign value =
+	Hashtbl.replace cs.cache.c_initialization_status sign value
 
 
 let get_context_files cs signs =
 let get_context_files cs signs =
 	Hashtbl.fold (fun (file,sign) cfile acc ->
 	Hashtbl.fold (fun (file,sign) cfile acc ->

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

@@ -151,7 +151,7 @@ let handler =
 		);
 		);
 		"server/readClassPaths", (fun hctx ->
 		"server/readClassPaths", (fun hctx ->
 			hctx.com.callbacks#add_after_init_macros (fun () ->
 			hctx.com.callbacks#add_after_init_macros (fun () ->
-				CompilationServer.set_initialized hctx.display#get_cs;
+				CompilationServer.set_initialized hctx.display#get_cs (Define.get_signature hctx.com.defines) true;
 				DisplayToplevel.read_class_paths hctx.com ["init"];
 				DisplayToplevel.read_class_paths hctx.com ["init"];
 				let files = CompilationServer.get_files hctx.display#get_cs in
 				let files = CompilationServer.get_files hctx.display#get_cs in
 				hctx.send_result (jobject [
 				hctx.send_result (jobject [

+ 31 - 28
src/context/display/displayToplevel.ml

@@ -59,7 +59,7 @@ let explore_class_paths com timer class_paths recusive f_pack f_module =
 									let name = String.sub file 0 (l - 3) in
 									let name = String.sub file 0 (l - 3) in
 									let path = (List.rev pack,name) in
 									let path = (List.rev pack,name) in
 									let dot_path = if dot_path = "" then name else dot_path ^ "." ^ name in
 									let dot_path = if dot_path = "" then name else dot_path ^ "." ^ name in
-									if (List.mem dot_path !exclude) then () else f_module path;
+									if (List.mem dot_path !exclude) then () else f_module (dir ^ file) path;
 								with _ ->
 								with _ ->
 									()
 									()
 							end
 							end
@@ -74,36 +74,39 @@ let explore_class_paths com timer class_paths recusive f_pack f_module =
 
 
 let read_class_paths com timer =
 let read_class_paths com timer =
 	let sign = Define.get_signature com.defines in
 	let sign = Define.get_signature com.defines in
-	explore_class_paths com timer (List.filter ((<>) "") com.class_path) true (fun _ -> ()) (fun path ->
-		let file,_,pack,_ = Display.parse_module' com path Globals.null_pos in
-		match CompilationServer.get() with
-		| Some cs when pack <> fst path ->
-			let file = Path.unique_full_path file in
-			CompilationServer.remove_file_for_real cs (file,sign)
-		| _ ->
-			()
+	explore_class_paths com timer (List.filter ((<>) "") com.class_path) true (fun _ -> ()) (fun file path ->
+		(* Don't parse the display file as that would maybe overwrite the content from stdin with the file contents. *)
+		if not (DisplayPosition.display_position#is_in_file file) then begin
+			let file,_,pack,_ = Display.parse_module' com path Globals.null_pos in
+			match CompilationServer.get() with
+			| Some cs when pack <> fst path ->
+				let file = Path.unique_full_path file in
+				CompilationServer.remove_file_for_real cs (file,sign)
+			| _ ->
+				()
+		end
 	)
 	)
 
 
 let init_or_update_server cs com timer_name =
 let init_or_update_server cs com timer_name =
-	if not (CompilationServer.is_initialized cs) then begin
-		CompilationServer.set_initialized cs;
+	let sign = Define.get_signature com.defines in
+	if not (CompilationServer.is_initialized cs sign) then begin
+		CompilationServer.set_initialized cs sign true;
 		read_class_paths com timer_name
 		read_class_paths com timer_name
-	end else begin
-		(* Iterate all removed files of the current context. If they aren't part of the context again,
-		   re-parse them and remove them from c_removed_files. *)
-		let sign = Define.get_signature com.defines in
-		let removed_removed_files = DynArray.create () in
-		Hashtbl.iter (fun (file,sign') () ->
-			if sign = sign' then begin
-				DynArray.add removed_removed_files (file,sign');
-				try
-					ignore(find_file cs (file,sign));
-				with Not_found ->
-					try ignore(TypeloadParse.parse_module_file com file null_pos) with _ -> ()
-			end;
-		) cs.cache.c_removed_files;
-		DynArray.iter (Hashtbl.remove cs.cache.c_removed_files) removed_removed_files;
-	end
+	end;
+	(* Iterate all removed files of the current context. If they aren't part of the context again,
+		re-parse them and remove them from c_removed_files. *)
+	let sign = Define.get_signature com.defines in
+	let removed_removed_files = DynArray.create () in
+	Hashtbl.iter (fun (file,sign') () ->
+		if sign = sign' then begin
+			DynArray.add removed_removed_files (file,sign');
+			try
+				ignore(find_file cs (file,sign));
+			with Not_found ->
+				try ignore(TypeloadParse.parse_module_file com file null_pos) with _ -> ()
+		end;
+	) cs.cache.c_removed_files;
+	DynArray.iter (Hashtbl.remove cs.cache.c_removed_files) removed_removed_files
 
 
 module CollectionContext = struct
 module CollectionContext = struct
 	open ImportStatus
 	open ImportStatus
@@ -386,7 +389,7 @@ let collect ctx tk with_type =
 		(* offline: explore class paths *)
 		(* offline: explore class paths *)
 		let class_paths = ctx.com.class_path in
 		let class_paths = ctx.com.class_path in
 		let class_paths = List.filter (fun s -> s <> "") class_paths in
 		let class_paths = List.filter (fun s -> s <> "") class_paths in
-		explore_class_paths ctx.com ["display";"toplevel"] class_paths true add_package (fun path ->
+		explore_class_paths ctx.com ["display";"toplevel"] class_paths true add_package (fun file path ->
 			if not (path_exists cctx path) then begin
 			if not (path_exists cctx path) then begin
 				let _,decls = Display.parse_module ctx path Globals.null_pos in
 				let _,decls = Display.parse_module ctx path Globals.null_pos in
 				ignore(process_decls (fst path) (snd path) decls)
 				ignore(process_decls (fst path) (snd path) decls)

+ 37 - 0
tests/server/src/DisplayTests.hx

@@ -189,4 +189,41 @@ typedef Foo = {
 		Assert.equals(transform.markers[1], r.replaceRange.start.character);
 		Assert.equals(transform.markers[1], r.replaceRange.start.character);
 		Assert.equals(transform.markers[2], r.replaceRange.end.character);
 		Assert.equals(transform.markers[2], r.replaceRange.end.character);
 	}
 	}
+
+	function testIssue8666() {
+		vfs.putContent("cp1/HelloWorld.hx", getTemplate("HelloWorld.hx"));
+		vfs.putContent("cp2/MyClass.hx", "class MyClass { }");
+		var args = ["-cp", "cp1", "--interp"];
+		runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
+		var completion = parseCompletion();
+		assertHasNoCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "MyClass";
+			case _: false;
+		});
+		runHaxeJson(args.concat(["-cp", "cp2"]), DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
+		var completion = parseCompletion();
+		assertHasCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "MyClass";
+			case _: false;
+		});
+	}
+
+	function testIssue8666_lib() {
+		vfs.putContent("cp1/HelloWorld.hx", getTemplate("HelloWorld.hx"));
+		vfs.putContent("cp2/MyClass.hx", "class MyClass { }");
+		var args = ["-cp", "cp1", "--interp"];
+		runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
+		var completion = parseCompletion();
+		assertHasNoCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "MyClass";
+			case _: false;
+		});
+		runHaxeJson(args.concat(["-cp", "cp2", "-D", "imalibrary"]), DisplayMethods.Completion,
+			{file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
+		var completion = parseCompletion();
+		assertHasCompletion(completion, module -> switch (module.kind) {
+			case Type: module.args.path.typeName == "MyClass";
+			case _: false;
+		});
+	}
 }
 }

+ 0 - 1
tests/server/src/Main.hx

@@ -140,7 +140,6 @@ class ServerTests extends HaxeServerTestCase {
 		vfs.putContent("Empty.hx", "");
 		vfs.putContent("Empty.hx", "");
 		runHaxeJson([], ServerMethods.ModuleCreated, {file: new FsPath("Empty.hx")});
 		runHaxeJson([], ServerMethods.ModuleCreated, {file: new FsPath("Empty.hx")});
 		vfs.putContent("Empty.hx", getTemplate("Empty.hx"));
 		vfs.putContent("Empty.hx", getTemplate("Empty.hx"));
-		runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Empty.hx")});
 		runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
 		runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false});
 		var completion = parseCompletion();
 		var completion = parseCompletion();
 		assertHasCompletion(completion, module -> switch (module.kind) {
 		assertHasCompletion(completion, module -> switch (module.kind) {