Jelajahi Sumber

[display] support signature completion on array access

closes #6775
Simon Krajewski 7 tahun lalu
induk
melakukan
8934ae309b

+ 1 - 1
src/compiler/main.ml

@@ -1018,7 +1018,7 @@ with
 	| DisplayException(DisplayHover ({hitem = {CompletionItem.ci_type = Some (t,_)}} as hover)) ->
 		let doc = CompletionItem.get_documentation hover.hitem in
 		raise (DisplayOutput.Completion (DisplayOutput.print_type t hover.hpos doc))
-	| DisplayException(DisplaySignatures(signatures,_,display_arg)) ->
+	| DisplayException(DisplaySignatures(signatures,_,display_arg,_)) ->
 		if ctx.com.display.dms_kind = DMSignature then
 			raise (DisplayOutput.Completion (DisplayOutput.print_signature signatures display_arg))
 		else

+ 13 - 8
src/context/display/display.ml

@@ -161,16 +161,21 @@ module ExprPreprocessing = struct
 
 	let find_display_call e =
 		let found = ref false in
+		let handle_el e el =
+			let call_arg_is_marked () =
+				el = [] || List.exists (fun (e,_) -> match e with EDisplay(_,DKMarked) -> true | _ -> false) el
+			in
+			if not !Parser.was_auto_triggered || call_arg_is_marked () then begin
+			found := true;
+			Parser.mk_display_expr e DKCall
+			end else
+				e
+		in
 		let loop e = match fst e with
 			| ECall(_,el) | ENew(_,el) when not !found && encloses_display_position (pos e) ->
-				let call_arg_is_marked () =
-					el = [] || List.exists (fun (e,_) -> match e with EDisplay(_,DKMarked) -> true | _ -> false) el
-				in
-				if not !Parser.was_auto_triggered || call_arg_is_marked () then begin
-				found := true;
-				Parser.mk_display_expr e DKCall
-				end else
-					e
+				handle_el e el
+			| EArray(e1,e2) when not !found && encloses_display_position (pos e2) ->
+				handle_el e [e2]
 			| EDisplay(_,DKCall) ->
 				raise Exit
 			| _ -> e

+ 12 - 3
src/context/display/displayException.ml

@@ -11,12 +11,16 @@ type hover_result = {
 	hexpected : WithType.t option;
 }
 
+type signature_kind =
+	| SKCall
+	| SKArrayAccess
+
 type kind =
 	| Diagnostics of string
 	| Statistics of string
 	| ModuleSymbols of string
 	| Metadata of string
-	| DisplaySignatures of ((tsignature * CompletionType.ct_function) * documentation) list * int * int
+	| DisplaySignatures of ((tsignature * CompletionType.ct_function) * documentation) list * int * int * signature_kind
 	| DisplayHover of hover_result
 	| DisplayPosition of pos list
 	| DisplayFields of CompletionItem.t list * CompletionResultKind.t * pos option (* insert pos *)
@@ -28,7 +32,7 @@ let raise_diagnostics s = raise (DisplayException(Diagnostics s))
 let raise_statistics s = raise (DisplayException(Statistics s))
 let raise_module_symbols s = raise (DisplayException(ModuleSymbols s))
 let raise_metadata s = raise (DisplayException(Metadata s))
-let raise_signatures l isig iarg = raise (DisplayException(DisplaySignatures(l,isig,iarg)))
+let raise_signatures l isig iarg kind = raise (DisplayException(DisplaySignatures(l,isig,iarg,kind)))
 let raise_hover item expected p = raise (DisplayException(DisplayHover({hitem = item;hpos = p;hexpected = expected})))
 let raise_position pl = raise (DisplayException(DisplayPosition pl))
 let raise_fields ckl cr po = raise (DisplayException(DisplayFields(ckl,cr,po)))
@@ -52,7 +56,7 @@ let to_json ctx de =
 	| Statistics _
 	| ModuleSymbols _
 	| Metadata _ -> assert false
-	| DisplaySignatures(sigs,isig,iarg) ->
+	| DisplaySignatures(sigs,isig,iarg,kind) ->
 		(* We always want full info for signatures *)
 		let ctx = Genjson.create_context GMFull in
 		let fsig ((_,signature),doc) =
@@ -60,10 +64,15 @@ let to_json ctx de =
 			let fl = (match doc with None -> fl | Some s -> ("documentation",jstring s) :: fl) in
 			jobject fl
 		in
+		let sigkind = match kind with
+			| SKCall -> 0
+			| SKArrayAccess -> 1
+		in
 		jobject [
 			"activeSignature",jint isig;
 			"activeParameter",jint iarg;
 			"signatures",jlist fsig sigs;
+			"kind",jint sigkind;
 		]
 	| DisplayHover hover ->
 		let name_source_kind_to_int = function

+ 5 - 17
src/syntax/grammar.mly

@@ -1281,8 +1281,9 @@ and expr_next' e1 = parser
 		| _ -> assert false)
 	| [< '(Dot,p); e = parse_field e1 p >] -> e
 	| [< '(POpen,p1); e = parse_call_params (fun el p2 -> (ECall(e1,el)),punion (pos e1) p2) p1; s >] -> expr_next e s
-	| [< '(BkOpen,_); e2 = secure_expr; s >] ->
+	| [< '(BkOpen,p1); e2 = secure_expr; s >] ->
 		let p2 = expect_unless_resume_p bkclose s in
+		let e2 = check_signature_mark e2 p1 p2 in
 		expr_next (EArray (e1,e2), punion (pos e1) p2) s
 	| [< '(Arrow,pa); s >] ->
 		let er = expr s in
@@ -1387,29 +1388,16 @@ and parse_call_params f p1 s =
 			| Stream.Error _ | Stream.Failure ->
 				mk_null_expr (punion_next p1 s)
 			in
-			let check_signature_mark e p2 =
-				if not (is_signature_display()) then e
-				else begin
-					let p = punion p1 p2 in
-					if true || not !was_auto_triggered then begin (* TODO: #6383 *)
-						if encloses_position_gt !display_position p then (mk_display_expr e DKMarked)
-						else e
-					end else begin
-						if !display_position.pmin = p1.pmax then (mk_display_expr e DKMarked)
-						else e
-					end
-				end
-			in
 			match s with parser
 			| [< '(PClose,p2) >] ->
-				let e = check_signature_mark e p2 in
+				let e = check_signature_mark e p1 p2 in
 				f (List.rev (e :: acc)) p2
 			| [< '(Comma,p2) >] ->
-				let e = check_signature_mark e p2 in
+				let e = check_signature_mark e p1 p2 in
 				parse_next_param (e :: acc) p2
 			| [< >] ->
 				let p2 = next_pos s in
-				let e = check_signature_mark e p2 in
+				let e = check_signature_mark e p1 p2 in
 				f (List.rev (e :: acc)) p2
 		in
 		match s with parser

+ 14 - 1
src/syntax/parser.ml

@@ -296,4 +296,17 @@ let check_type_decl_completion mode pmax s =
 		(* print_endline (Printf.sprintf "(%i <= %i) (%i >= %i)" pmax !display_position.pmin pmin !display_position.pmax); *)
 		if pmax <= !display_position.pmin && pmin >= !display_position.pmax then
 			delay_syntax_completion (SCTypeDecl mode) !display_position
-	end;
+	end
+
+let check_signature_mark e p1 p2 =
+	if not (is_signature_display()) then e
+	else begin
+		let p = punion p1 p2 in
+		if true || not !was_auto_triggered then begin (* TODO: #6383 *)
+			if encloses_position_gt !display_position p then (mk_display_expr e DKMarked)
+			else e
+		end else begin
+			if !display_position.pmin = p1.pmax then (mk_display_expr e DKMarked)
+			else e
+		end
+	end

+ 23 - 3
src/typing/typerDisplay.ml

@@ -183,7 +183,7 @@ let rec handle_signature_display ctx e_ast with_type =
 		in
 		let overloads = match loop [] tl with [] -> tl | tl -> tl in
 		let overloads = List.map (fun (t,doc,values) -> (convert_function_signature ctx values t,doc)) overloads in
-		raise_signatures overloads 0 (* ? *) display_arg
+		raise_signatures overloads 0 (* ? *) display_arg SKCall
 	in
 	let find_constructor_types t = match follow t with
 		| TInst ({cl_kind = KTypeParameter tl} as c,_) ->
@@ -233,6 +233,26 @@ let rec handle_signature_display ctx e_ast with_type =
 		| ENew(tpath,el) ->
 			let t = Typeload.load_instance ctx tpath true in
 			handle_call (find_constructor_types t) el (pos tpath)
+		| EArray(e1,e2) ->
+			let e1 = type_expr ctx e1 WithType.value in
+			begin match follow e1.etype with
+			| TInst({cl_path=([],"Array")},[t]) ->
+				let res = convert_function_signature ctx PMap.empty (["index",false,ctx.t.tint],t) in
+				raise_signatures [res,Some "The array index"] 0 0 SKCall
+			| TAbstract(a,tl) ->
+				(match a.a_impl with Some c -> ignore(c.cl_build()) | _ -> ());
+				let sigs = ExtList.List.filter_map (fun cf -> match follow cf.cf_type with
+					| TFun(_ :: (n,o,t) :: _,r) ->
+						let t = apply_params a.a_params tl t in
+						let r = apply_params a.a_params tl r in
+						Some (convert_function_signature ctx PMap.empty ([(n,o,t)],r),cf.cf_doc)
+					| _ ->
+						None
+				) a.a_array in
+				raise_signatures sigs 0 0 SKArrayAccess
+			| _ ->
+				raise_signatures [] 0 0 SKArrayAccess
+			end
 		| _ -> error "Call expected" p
 
 and display_expr ctx e_ast e dk with_type p =
@@ -395,7 +415,7 @@ let handle_display ctx e_ast dk with_type =
 		let arg = ["expression",false,mono] in
 		begin match ctx.com.display.dms_kind with
 		| DMSignature ->
-			raise_signatures [(convert_function_signature ctx PMap.empty (arg,mono),doc)] 0 0
+			raise_signatures [(convert_function_signature ctx PMap.empty (arg,mono),doc)] 0 0 SKCall
 		| _ ->
 			let t = TFun(arg,mono) in
 			raise_hover (make_ci_expr (mk (TIdent "trace") t (pos e_ast)) (tpair t)) (Some (WithType.named_argument "expression")) (pos e_ast);
@@ -406,7 +426,7 @@ let handle_display ctx e_ast dk with_type =
 		let ret = ctx.com.basic.tvoid in
 		begin match ctx.com.display.dms_kind with
 		| DMSignature ->
-			raise_signatures [(convert_function_signature ctx PMap.empty (arg,ret),doc)] 0 0
+			raise_signatures [(convert_function_signature ctx PMap.empty (arg,ret),doc)] 0 0 SKCall
 		| _ ->
 			let t = TFun(arg,ret) in
 			raise_hover (make_ci_expr (mk (TIdent "trace") t (pos e_ast)) (tpair t)) (Some (WithType.named_argument "value")) (pos e_ast);

+ 96 - 0
tests/display/src/cases/ArrayAccessSignature.hx

@@ -0,0 +1,96 @@
+package cases;
+
+import SignatureHelp;
+
+class ArrayAccessSignature extends DisplayTestCase {
+	/**
+	class Some {
+		function main() {
+			[][{-1-}
+		}
+	}
+	**/
+	function testArray1() {
+		sigEq(0, [["index:Int"]], signature(pos(1)));
+	}
+
+	/**
+	class Some {
+		function main() {
+			[][{-1-}]
+		}
+	}
+	**/
+	function testArray2() {
+		sigEq(0, [["index:Int"]], signature(pos(1)));
+	}
+
+	/**
+	class Some {
+		function main() {
+			[][1{-1-}
+		}
+	}
+	**/
+	function testArray3() {
+		sigEq(0, [["index:Int"]], signature(pos(1)));
+	}
+
+	/**
+	class Some {
+		function main() {
+			[][1{-1-}]
+		}
+	}
+	**/
+	function testArray4() {
+		sigEq(0, [["index:Int"]], signature(pos(1)));
+	}
+
+	/**
+	class Some {
+		function main() {
+			[][1{-1-}2
+		}
+	}
+	**/
+	function testArray5() {
+		sigEq(0, [["index:Int"]], signature(pos(1)));
+	}
+
+	/**
+	class Some {
+		function main() {
+			[][1{-1-}2]
+		}
+	}
+	**/
+	function testArray6() {
+		sigEq(0, [["index:Int"]], signature(pos(1)));
+	}
+
+	/**
+	class Some {
+		function main() {
+			[1 => 2][{-1-}
+		}
+	}
+	**/
+	function testMap1() {
+		// because screw consistency
+		sigEq(0, [["key:Int"], ["k:Int"]], signature(pos(1)));
+	}
+
+	/**
+	class Some {
+		function main() {
+			call([1 => 2][{-1-}
+		}
+
+		static function call(i1:Int, i2:Int) { }
+	}
+	**/
+	function testInCall1() {
+		sigEq(0, [["key:Int"], ["k:Int"]], signature(pos(1)));
+	}
+}