瀏覽代碼

[display] filter constructible types in `new |` completion

closes #7051
Simon Krajewski 7 年之前
父節點
當前提交
c04c4b15f4

+ 30 - 8
src/core/display/completionItem.ml

@@ -40,6 +40,11 @@ end
 module CompletionModuleType = struct
 	open CompletionModuleKind
 
+	type not_bool =
+		| Yes
+		| No
+		| Maybe
+
 	type t = {
 		pack : string list;
 		name : string;
@@ -52,10 +57,16 @@ module CompletionModuleType = struct
 		is_extern : bool;
 		kind : CompletionModuleKind.t;
 		import_status : ImportStatus.t;
+		has_constructor : not_bool;
 	}
 
 	let of_type_decl is pack module_name (td,p) = match td with
-		| EClass d -> {
+		| EClass d ->
+			let ctor = if (List.exists (fun cff -> fst cff.cff_name = "new") d.d_data) then Yes
+				else if (List.exists (function HExtends _ -> true | _ -> false) d.d_flags) then Maybe
+				else No
+			in
+			{
 				pack = pack;
 				name = fst d.d_name;
 				module_name = module_name;
@@ -67,6 +78,7 @@ module CompletionModuleType = struct
 				is_extern = List.mem HExtern d.d_flags;
 				kind = if List.mem HInterface d.d_flags then Interface else Class;
 				import_status = is;
+				has_constructor = ctor;
 			}
 		| EEnum d -> {
 				pack = pack;
@@ -80,8 +92,11 @@ module CompletionModuleType = struct
 				is_extern = List.mem EExtern d.d_flags;
 				kind = Enum;
 				import_status = is;
+				has_constructor = No;
 			}
-		| ETypedef d -> {
+		| ETypedef d ->
+			let kind = match fst d.d_data with CTAnonymous _ -> Struct | _ -> TypeAlias in
+			{
 				pack = pack;
 				name = fst d.d_name;
 				module_name = module_name;
@@ -91,8 +106,9 @@ module CompletionModuleType = struct
 				meta = d.d_meta;
 				doc = d.d_doc;
 				is_extern = List.mem EExtern d.d_flags;
-				kind = (match fst d.d_data with CTAnonymous _ -> Struct | _ -> TypeAlias);
+				kind = kind;
 				import_status = is;
+				has_constructor = if kind = Struct then No else Maybe;
 			}
 		| EAbstract d -> {
 				pack = pack;
@@ -106,20 +122,25 @@ module CompletionModuleType = struct
 				is_extern = List.mem AbExtern d.d_flags;
 				kind = if Meta.has Meta.Enum d.d_meta then EnumAbstract else Abstract;
 				import_status = is;
+				has_constructor = if (List.exists (fun cff -> fst cff.cff_name = "new") d.d_data) then Yes else No;
 			}
 		| EImport _ | EUsing _ ->
 			raise Exit
 
 	let of_module_type is mt =
-		let is_extern,kind = match mt with
+		let is_extern,kind,has_ctor = match mt with
 			| TClassDecl c ->
-				c.cl_extern,if c.cl_interface then Interface else Class
+				c.cl_extern,(if c.cl_interface then Interface else Class),has_constructor c
 			| TEnumDecl en ->
-				en.e_extern,Enum
+				en.e_extern,Enum,false
 			| TTypeDecl td ->
-				false,(match follow td.t_type with TAnon _ -> Struct | _ -> TypeAlias)
+				false,(match follow td.t_type with TAnon _ -> Struct | _ -> TypeAlias),false
 			| TAbstractDecl a ->
-				false,(if Meta.has Meta.Enum a.a_meta then EnumAbstract else Abstract)
+				let has_ctor = match a.a_impl with
+					| None -> false
+					| Some c -> PMap.mem "_new" c.cl_statics
+				in
+				false,(if Meta.has Meta.Enum a.a_meta then EnumAbstract else Abstract),has_ctor
 		in
 		let infos = t_infos mt in
 		let convert_type_param (s,t) = match follow t with
@@ -144,6 +165,7 @@ module CompletionModuleType = struct
 			is_extern = is_extern;
 			kind = kind;
 			import_status = is;
+			has_constructor = if has_ctor then Yes else No;
 		}
 
 	let get_path cm = (cm.pack,cm.name)

+ 6 - 0
src/core/type.ml

@@ -921,6 +921,12 @@ let rec get_constructor build_type c =
 		let t, c = get_constructor build_type csup in
 		apply_params csup.cl_params cparams t, c
 
+let has_constructor c =
+	try
+		ignore(get_constructor (fun cf -> cf.cf_type) c);
+		true
+	with Not_found -> false
+
 (* ======= Printing ======= *)
 
 let print_context() = ref []

+ 19 - 1
src/typing/typerDisplay.ml

@@ -287,10 +287,28 @@ let handle_display ctx e_ast dk with_type =
 			raise err
 		end
 	| DisplayException(DisplayFields(l,CRTypeHint,p,b)) when (match fst e_ast with ENew _ -> true | _ -> false) ->
+		let timer = Timer.timer ["display";"toplevel";"filter ctors"] in
+		ctx.pass <- PBuildClass;
 		let l = List.filter (function
-			| ITType({kind = (Class | Abstract)},_) -> true
+			| ITType({kind = (Class | Abstract)} as mt,_) when not mt.is_private ->
+				begin match mt.has_constructor with
+				| Yes -> true
+				| No -> false
+				| Maybe ->
+					begin try
+						let mt = ctx.g.do_load_type_def ctx null_pos {tpackage=mt.pack;tname=mt.module_name;tsub=Some mt.name;tparams=[]} in
+						begin match mt with
+						| TClassDecl c when has_constructor c -> true
+						| TAbstractDecl {a_impl = Some c} -> PMap.mem "_new" c.cl_statics
+						| _ -> false
+						end
+					with _ ->
+						false
+					end
+				end
 			| _ -> false
 		) l in
+		timer();
 		raise_fields l CRNew p b
 	in
 	let is_display_debug = Meta.has (Meta.Custom ":debug.display") ctx.curfield.cf_meta in

+ 5 - 1
tests/display/src/cases/Issue7029.hx

@@ -85,12 +85,16 @@ class Issue7029 extends DisplayTestCase {
 	interface I1 {}
 	typedef T1 = {};
 	enum E1 {}
-	class C1 {}
+	class C1 {
+		public function new() { }
+	}
 
 	class C2 {
 		static function main() {
 			new{-1-}   {-2-}
 		}
+
+		public function new() { }
 	}
 	**/
 	function test7() {

+ 35 - 0
tests/display/src/cases/Issue7051.hx

@@ -0,0 +1,35 @@
+package cases;
+
+class Issue7051 extends DisplayTestCase {
+	/**
+	class CWithCtor {
+		public function new() { }
+	}
+	class CInheritedCtor extends CWithCtor { }
+	class CInheritedCtor2 extends CInheritedCtor { }
+	class CNoCtor { }
+	class CNoCtor2 extends CNoCtor { }
+
+	abstract AWithCtor(String) {
+		public function new() this = "";
+	}
+	abstract AWithoutCtor(String) { }
+
+	class Main {
+		static function main() {
+			new {-1-}
+		}
+	}
+	**/
+	function test() {
+		var toplevel = toplevel(pos(1));
+		eq(true, hasToplevel(toplevel, "type", "CWithCtor"));
+		eq(true, hasToplevel(toplevel, "type", "CInheritedCtor"));
+		eq(true, hasToplevel(toplevel, "type", "CInheritedCtor2"));
+		eq(false, hasToplevel(toplevel, "type", "CNoCtor"));
+		eq(false, hasToplevel(toplevel, "type", "CNoCtor2"));
+
+		eq(true, hasToplevel(toplevel, "type", "AWithCtor"));
+		eq(false, hasToplevel(toplevel, "type", "AWithoutCtor"));
+	}
+}