Browse Source

[display] support missing property accessor diagnostic

Simon Krajewski 5 years ago
parent
commit
ca1765c61d

+ 2 - 0
src/context/common.ml

@@ -244,8 +244,10 @@ type shared_display_information = {
 type missing_field_cause =
 	| AbstractParent of tclass * tparams
 	| ImplementedInterface of tclass * tparams
+	| PropertyAccessor of tclass_field * bool (* true = getter *)
 
 and missing_fields_diagnostics = {
+	mf_pos : pos;
 	mf_on : tclass;
 	mf_fields : (tclass_field * Type.t * CompletionItem.CompletionType.t) list;
 	mf_cause : missing_field_cause;

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

@@ -152,7 +152,7 @@ let prepare com =
 		) com.modules;
 		List.iter (function
 			| MissingFields mf ->
-				let p = mf.mf_on.cl_name_pos in
+				let p = mf.mf_pos in
 				begin try
 					let _,l = PMap.find p dctx.missing_fields in
 					l := mf :: !l

+ 10 - 2
src/context/display/diagnosticsPrinter.ml

@@ -5,7 +5,7 @@ open DisplayTypes
 open DiagnosticsKind
 open DisplayTypes
 open DiagnosticsTypes
-open TType
+open Type
 open Genjson
 
 type t = DiagnosticsKind.t * pos
@@ -80,6 +80,9 @@ let json_of_diagnostics dctx =
 	PMap.iter (fun p (c,mfl) ->
 		let jctx = create_context GMMinimum in
 		let all_fields = ref [] in
+		let scope cf =
+			if has_class_field_flag cf CfStatic then CFSStatic else CFSMember
+		in
 		let create mf =
 			let kind,args = match mf.mf_cause with
 				| AbstractParent(csup,tl) ->
@@ -90,6 +93,11 @@ let json_of_diagnostics dctx =
 					"ImplementedInterface",jobject [
 						"parent",generate_type_path_with_params jctx ci.cl_module.m_path ci.cl_path tl ci.cl_meta;
 					]
+				| PropertyAccessor(cf,is_getter) ->
+					"PropertyAccessor",jobject [
+						"property",generate_class_field jctx (scope cf) cf;
+						"isGetter",jbool is_getter;
+					]
 			in
 			let current_fields = ref [] in
 			let map_field (cf,t,ct) =
@@ -102,7 +110,7 @@ let json_of_diagnostics dctx =
 					current_fields := (t,cf) :: !current_fields;
 					all_fields := (t,cf) :: !all_fields;
 					Some (jobject [
-						"field",generate_class_field jctx CFSMember cf;
+						"field",generate_class_field jctx (scope cf) cf;
 						"type",CompletionType.generate_type jctx ct;
 						"unique",jbool unique;
 					])

+ 2 - 0
src/typing/typeloadCheck.ml

@@ -417,6 +417,7 @@ module Inheritance = struct
 			if DynArray.length missing > 0 then begin
 				let l = DynArray.to_list missing in
 				let diag = {
+					mf_pos = c.cl_name_pos;
 					mf_on = c;
 					mf_fields = List.map (fun (cf,t) -> (cf,t,CompletionType.from_type (Display.get_import_status ctx) t)) l;
 					mf_cause = ImplementedInterface(intf,params);
@@ -452,6 +453,7 @@ module Inheritance = struct
 			()
 		| l when Diagnostics.is_diagnostics_run ctx.com c.cl_pos ->
 			let diag = {
+				mf_pos = c.cl_name_pos;
 				mf_on = c;
 				mf_fields = List.rev_map (fun (cf,t) -> (cf,t,CompletionType.from_type (Display.get_import_status ctx) t)) l;
 				mf_cause = AbstractParent(csup,params);

+ 27 - 11
src/typing/typeloadFields.ml

@@ -1269,7 +1269,12 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p =
 			else match class_field c (List.map snd c.cl_params) m with
 				| _, t,f -> t,f ]
 	in
-	let check_method m t =
+	let cf = {
+		(mk_field name ~public:(is_public (ctx,cctx) f.cff_access None) ret f.cff_pos (pos f.cff_name)) with
+		cf_doc = f.cff_doc;
+		cf_meta = f.cff_meta;
+	} in
+	let check_method m t is_getter =
 		if ctx.com.display.dms_error_policy = EPIgnore then () else
 		try
 			let overloads = find_accessor m in
@@ -1282,7 +1287,7 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p =
 					else
 						get_overload overl
 				| [] ->
-					if (has_class_flag c CInterface) then
+					if (has_class_flag c CInterface) || Diagnostics.is_diagnostics_run ctx.com f.cff_pos then
 						raise Not_found
 					else
 						raise (Error (Custom
@@ -1305,12 +1310,28 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p =
 		with
 			| Error (Unify l,p) -> raise (Error (Stack (Custom ("In method " ^ m ^ " required by property " ^ name),Unify l),p))
 			| Not_found ->
-				if (has_class_flag c CInterface) then begin
+				let generate_field () =
 					let cf = mk_field m t p null_pos in
 					cf.cf_meta <- [Meta.CompilerGenerated,[],null_pos;Meta.NoCompletion,[],null_pos];
 					cf.cf_kind <- Method MethNormal;
+					cf
+				in
+				if (has_class_flag c CInterface) then begin
+					let cf = generate_field () in
 					c.cl_fields <- PMap.add cf.cf_name cf c.cl_fields;
 					c.cl_ordered_fields <- cf :: c.cl_ordered_fields;
+				end else if Diagnostics.is_diagnostics_run ctx.com f.cff_pos then begin
+					let cf_accessor = generate_field() in
+					remove_class_field_flag cf_accessor CfPublic;
+					if fctx.is_static then add_class_field_flag cf_accessor CfStatic;
+					let diag = {
+						mf_pos = (pos f.cff_name);
+						mf_on = c;
+						mf_fields = [(cf_accessor,t,CompletionItem.CompletionType.from_type (Display.get_import_status ctx) t)];
+						mf_cause = PropertyAccessor(cf,is_getter);
+					} in
+					let display = ctx.com.display_information in
+					display.module_diagnostics <- MissingFields diag :: display.module_diagnostics
 				end else if not (has_class_flag c CExtern) then begin
 					try
 						let _, _, f2 = (if not fctx.is_static then let f = PMap.find m c.cl_statics in None, f.cf_type, f else class_field c (List.map snd c.cl_params) m) in
@@ -1335,7 +1356,7 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p =
 		| "get",pget ->
 			let get = "get_" ^ name in
 			if fctx.is_display_field && DisplayPosition.display_position#enclosed_in pget then delay ctx PConnectField (fun () -> display_accessor get pget);
-			if not cctx.is_lib then delay_check (fun() -> check_method get t_get);
+			if not cctx.is_lib then delay_check (fun() -> check_method get t_get true);
 			AccCall
 		| _,pget ->
 			display_error ctx (name ^ ": Custom property accessor is no longer supported, please use `get`") pget;
@@ -1354,19 +1375,14 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p =
 		| "set",pset ->
 			let set = "set_" ^ name in
 			if fctx.is_display_field && DisplayPosition.display_position#enclosed_in pset then delay ctx PConnectField (fun () -> display_accessor set pset);
-			if not cctx.is_lib then delay_check (fun() -> check_method set t_set);
+			if not cctx.is_lib then delay_check (fun() -> check_method set t_set false);
 			AccCall
 		| _,pset ->
 			display_error ctx (name ^ ": Custom property accessor is no longer supported, please use `set`") pset;
 			AccCall
 	) in
 	if (set = AccNever && get = AccNever)  then error (name ^ ": Unsupported property combination") p;
-	let cf = {
-		(mk_field name ~public:(is_public (ctx,cctx) f.cff_access None) ret f.cff_pos (pos f.cff_name)) with
-		cf_doc = f.cff_doc;
-		cf_meta = f.cff_meta;
-		cf_kind = Var { v_read = get; v_write = set };
-	} in
+	cf.cf_kind <- Var { v_read = get; v_write = set };
 	if fctx.is_extern then add_class_field_flag cf CfExtern;
 	ctx.curfield <- cf;
 	bind_var (ctx,cctx,fctx) cf eo;