ソースを参照

[display] improve support for reference display on type-hints

see #5696
Simon Krajewski 7 年 前
コミット
c55a3efb40

+ 3 - 1
src/compiler/displayOutput.ml

@@ -447,6 +447,8 @@ module StatisticsPrinter = struct
 		| SKClass _ -> "class type"
 		| SKInterface _ -> "interface type"
 		| SKEnum _ -> "enum type"
+		| SKTypedef _ -> "typedef"
+		| SKAbstract _ -> "abstract"
 		| SKField _ -> "class field"
 		| SKEnumField _ -> "enum field"
 		| SKVariable _ -> "variable"
@@ -746,7 +748,7 @@ let process_global_display_mode com tctx = match com.display.dms_kind with
 			| [] -> acc
 		in
 		let usages = Hashtbl.fold (fun p sym acc ->
-			if Statistics.is_usage_symbol sym then begin
+			if p = !Display.reference_position then begin
 				let acc = if with_definition then p :: acc else acc in
 				(try loop acc (Hashtbl.find relations p)
 				with Not_found -> acc)

+ 0 - 2
src/context/common.ml

@@ -105,7 +105,6 @@ type compiler_callback = {
 type shared_display_information = {
 	mutable import_positions : (pos,bool ref * placed_name list) PMap.t;
 	mutable diagnostics_messages : (string * pos * DisplayTypes.DiagnosticsSeverity.t) list;
-	mutable type_hints : (pos,Type.t) Hashtbl.t;
 	mutable document_symbols : (string * DisplayTypes.SymbolInformation.t DynArray.t) list;
 	mutable removable_code : (string * pos * pos) list;
 }
@@ -498,7 +497,6 @@ let create version s_version args =
 			shared_display_information = {
 				import_positions = PMap.empty;
 				diagnostics_messages = [];
-				type_hints = Hashtbl.create 0;
 				document_symbols = [];
 				removable_code = [];
 			}

+ 36 - 27
src/context/display.ml

@@ -100,11 +100,17 @@ module ExprPreprocessing = struct
 			end else
 				false
 		in
-		let loop e =
-			if is_annotated (pos e) then
-				(EDisplay(e,dk),(pos e))
-			else
-				e
+		let loop e = match fst e with
+			| EVars vl ->
+				if List.exists (fun ((_,p),_,_) -> is_annotated p) vl then
+					(EDisplay(e,dk),(pos e))
+				else
+					e
+			| _ ->
+				if is_annotated (pos e) then
+					(EDisplay(e,dk),(pos e))
+				else
+					e
 		in
 		let rec map e =
 			loop (Ast.map_expr map e)
@@ -155,7 +161,8 @@ module DisplayEmitter = struct
 
 	let check_display_type ctx t p =
 		let add_type_hint () =
-			Hashtbl.replace ctx.com.shared.shared_display_information.type_hints p t;
+			let md = ctx.m.curmod.m_extra.m_display in
+			md.m_type_hints <- (p,t) :: md.m_type_hints;
 		in
 		let maybe_display_type () =
 			if ctx.is_display_file && is_display_position p then
@@ -582,20 +589,12 @@ module Statistics = struct
 		| SKClass of tclass
 		| SKInterface of tclass
 		| SKEnum of tenum
+		| SKTypedef of tdef
+		| SKAbstract of tabstract
 		| SKField of tclass_field
 		| SKEnumField of tenum_field
 		| SKVariable of tvar
 
-	let is_usage_symbol symbol =
-		let p = match symbol with
-			| SKClass c | SKInterface c -> c.cl_name_pos
-			| SKEnum en -> en.e_name_pos
-			| SKField cf -> cf.cf_name_pos
-			| SKEnumField ef -> ef.ef_name_pos
-			| SKVariable v -> v.v_pos
-		in
-		!reference_position = p
-
 	let collect_statistics ctx =
 		let relations = Hashtbl.create 0 in
 		let symbols = Hashtbl.create 0 in
@@ -635,7 +634,6 @@ module Statistics = struct
 		in
 		let var_decl v = declare (SKVariable v) v.v_pos in
 		let patch_string_pos p s = { p with pmin = p.pmax - String.length s } in
-		let patch_string_pos_front p s  = { p with pmax = p.pmin + String.length s } in
 		let field_reference cf p =
 			add_relation cf.cf_name_pos (Referenced,patch_string_pos p cf.cf_name)
 		in
@@ -686,13 +684,26 @@ module Statistics = struct
 			in
 			loop e
 		in
+		let rec explore_type_hint (p,t) =
+			match t with
+			| TMono r -> (match !r with None -> () | Some t -> explore_type_hint (p,t))
+			| TLazy f -> explore_type_hint (p,lazy_type f)
+			| TInst(({cl_name_pos = pn;cl_path = (_,name)}),_)
+			| TEnum(({e_name_pos = pn;e_path = (_,name)}),_)
+			| TType(({t_name_pos = pn;t_path = (_,name)}),_)
+			| TAbstract(({a_name_pos = pn;a_path = (_,name)}),_) ->
+				add_relation pn (Referenced,p)
+			| TDynamic _ -> ()
+			| TFun _ | TAnon _ -> ()
+		in
 		let handled_modules = Hashtbl.create 0 in
 		let check_module m =
 			if not (Hashtbl.mem handled_modules m.m_path) then begin
 				Hashtbl.add handled_modules m.m_path true;
 				List.iter (fun (p1,p2) ->
 					add_relation p1 (Referenced,p2)
-				) m.m_extra.m_display.m_inline_calls
+				) m.m_extra.m_display.m_inline_calls;
+				List.iter explore_type_hint m.m_extra.m_display.m_type_hints
 			end
 		in
 		let f = function
@@ -714,10 +725,15 @@ module Statistics = struct
 				List.iter field c.cl_ordered_fields;
 				List.iter field c.cl_ordered_statics;
 			| TEnumDecl en ->
+				check_module en.e_module;
 				declare (SKEnum en) en.e_name_pos;
 				PMap.iter (fun _ ef -> declare (SKEnumField ef) ef.ef_name_pos) en.e_constrs
-			| _ ->
-				()
+			| TTypeDecl td ->
+				check_module td.t_module;
+				declare (SKTypedef td) td.t_name_pos
+			| TAbstractDecl a ->
+				check_module a.a_module;
+				declare (SKAbstract a) a.a_name_pos
 		in
 		begin match CompilationServer.get () with
 			| None -> List.iter f ctx.com.types
@@ -725,13 +741,6 @@ module Statistics = struct
 				CompilationServer.cache_context cs ctx.com;
 				CompilationServer.iter_modules cs ctx.com (fun m -> List.iter f m.m_types);
 		end;
-		let explore_type_hint p t = match follow t with
-			| TInst(c,_) -> add_relation c.cl_name_pos (Referenced,(patch_string_pos_front p (snd c.cl_path)))
-			| _ -> ()
-		in
-		Hashtbl.iter (fun p t ->
-			explore_type_hint p t
-		) ctx.com.shared.shared_display_information.type_hints;
 		let l = List.fold_left (fun acc (_,cfi,_,cfo) -> match cfo with
 			| Some cf -> if List.mem_assoc cf.cf_name_pos acc then acc else (cf.cf_name_pos,cfi.cf_name_pos) :: acc
 			| None -> acc

+ 2 - 0
src/core/type.ml

@@ -310,6 +310,7 @@ and module_def = {
 
 and module_def_display = {
 	mutable m_inline_calls : (pos * pos) list; (* calls whatever is at pos1 from pos2 *)
+	mutable m_type_hints : (pos * t) list;
 }
 
 and module_def_extra = {
@@ -424,6 +425,7 @@ let module_extra file sign time kind policy =
 		m_sign = sign;
 		m_display = {
 			m_inline_calls = [];
+			m_type_hints = [];
 		};
 		m_dirty = None;
 		m_added = 0;

+ 6 - 6
src/typing/typeloadModule.ml

@@ -625,13 +625,13 @@ let init_module_type ctx context_init do_init (decl,p) =
 			let ctx = { ctx with type_params = params @ ctx.type_params } in
 			let rt = (match c.ec_type with
 				| None -> et
-				| Some t ->
-					let t = load_complex_type ctx true p t in
+				| Some (t,pt) ->
+					let t = load_complex_type ctx true p (t,pt) in
 					(match follow t with
 					| TEnum (te,_) when te == e ->
 						()
 					| _ ->
-						error "Explicit enum type must be of the same enum type" p);
+						error "Explicit enum type must be of the same enum type" pt);
 					t
 			) in
 			let t = (match c.ec_args with
@@ -640,13 +640,13 @@ let init_module_type ctx context_init do_init (decl,p) =
 					is_flat := false;
 					let pnames = ref PMap.empty in
 					TFun (List.map (fun (s,opt,(t,tp)) ->
-						(match t with CTPath({tpackage=[];tname="Void"}) -> error "Arguments of type Void are not allowed in enum constructors" c.ec_pos | _ -> ());
+						(match t with CTPath({tpackage=[];tname="Void"}) -> error "Arguments of type Void are not allowed in enum constructors" tp | _ -> ());
 						if PMap.mem s (!pnames) then error ("Duplicate parameter '" ^ s ^ "' in enum constructor " ^ fst c.ec_name) p;
 						pnames := PMap.add s () (!pnames);
 						s, opt, load_type_hint ~opt ctx p (Some (t,tp))
 					) l, rt)
 			) in
-			if PMap.mem (fst c.ec_name) e.e_constrs then error ("Duplicate constructor " ^ fst c.ec_name) p;
+			if PMap.mem (fst c.ec_name) e.e_constrs then error ("Duplicate constructor " ^ fst c.ec_name) (pos c.ec_name);
 			let f = {
 				ef_name = fst c.ec_name;
 				ef_type = t;
@@ -666,7 +666,7 @@ let init_module_type ctx context_init do_init (decl,p) =
 				cf_doc = f.ef_doc;
 				cf_params = f.ef_params;
 			} in
- 			if ctx.is_display_file && Display.is_display_position p then
+ 			if ctx.is_display_file && Display.is_display_position f.ef_name_pos then
  				Display.DisplayEmitter.display_enum_field ctx.com.display f p;
 			e.e_constrs <- PMap.add f.ef_name f e.e_constrs;
 			fields := PMap.add cf.cf_name cf !fields;

+ 83 - 0
tests/display/src/cases/TypeHints.hx

@@ -0,0 +1,83 @@
+package cases;
+
+class TypeHints extends DisplayTestCase {
+	/**
+	typedef T1 = {-12-}T{-4-}2{-13-};
+	typedef T{-3-}2 = {-10-}C{-2-}1{-11-};
+	class C{-1-}1 { }
+	**/
+	function testTypedef1() {
+		arrayEq([range(12, 13)], usage(pos(3)));
+		arrayEq([range(12, 13)], usage(pos(4)));
+		arrayEq([range(10, 11)], usage(pos(1)));
+		arrayEq([range(10, 11)], usage(pos(2)));
+	}
+
+	/**
+	typedef T1 = {
+		var f1:{-10-}C{-1-}1{-11-};
+		var f2:{-12-}C1{-13-};
+	}
+
+	class C{-2-}1 { }
+	**/
+	function testStructure1() {
+		arrayEq([range(10, 11), range(12, 13)], usage(pos(1)));
+		arrayEq([range(10, 11), range(12, 13)], usage(pos(2)));
+	}
+
+	/**
+	enum E1 {
+		C1(c:{-10-}C{-1-}1{-11-});
+		C2(c:Int, d:{-12-}C{-2-}1{-13-});
+	}
+
+	class C{-3-}1 { }
+	**/
+	function testEnum1() {
+		arrayEq([range(10, 11), range(12, 13)], usage(pos(1)));
+		arrayEq([range(10, 11), range(12, 13)], usage(pos(2)));
+		arrayEq([range(10, 11), range(12, 13)], usage(pos(3)));
+	}
+
+	/**
+	abstract A1({-10-}C{-1-}1{-11-}) from {-12-}C{-2-}1{-13-} to {-14-}C{-3-}1{-15-} { }
+
+	class C{-4-}1 { }
+	**/
+	function testAbstract1() {
+		arrayEq([range(10, 11), range(12, 13), range(14, 15)], usage(pos(1)));
+		arrayEq([range(10, 11), range(12, 13), range(14, 15)], usage(pos(2)));
+		arrayEq([range(10, 11), range(12, 13), range(14, 15)], usage(pos(3)));
+		arrayEq([range(10, 11), range(12, 13), range(14, 15)], usage(pos(4)));
+	}
+
+	/**
+	class C{-1-}1 {
+		static function test(c:{-10-}C{-2-}1{-11-}):{-12-}C{-3-}1{-13-} { }
+	}
+	**/
+	function testFunction1() {
+		arrayEq([range(10, 11), range(12, 13)], usage(pos(1)));
+		arrayEq([range(10, 11), range(12, 13)], usage(pos(2)));
+		arrayEq([range(10, 11), range(12, 13)], usage(pos(3)));
+	}
+
+	/**
+	class C{-1-}1 { }
+	class C2 extends {-10-}C{-2-}1{-11-} { }
+	**/
+	function testClass1() {
+		arrayEq([range(10, 11)], usage(pos(1)));
+		arrayEq([range(10, 11)], usage(pos(2)));
+	}
+
+	/**
+	interface I{-1-}1 { }
+	class C2 implements {-10-}I{-2-}1{-11-} { }
+	**/
+	function testInterface1() {
+		arrayEq([range(10, 11)], usage(pos(1)));
+		arrayEq([range(10, 11)], usage(pos(2)));
+	}
+}