Răsfoiți Sursa

mark accessors of removed properties (closes #2509)

Simon Krajewski 11 ani în urmă
părinte
comite
050c36e42f
5 a modificat fișierele cu 65 adăugiri și 6 ștergeri
  1. 1 0
      ast.ml
  2. 10 6
      codegen.ml
  3. 1 0
      common.ml
  4. 27 0
      dce.ml
  5. 26 0
      tests/unit/TestDCE.hx

+ 1 - 0
ast.ml

@@ -30,6 +30,7 @@ module Meta = struct
 	type strict_meta =
 		| Abstract
 		| Access
+		| Accessor
 		| Allow
 		| Annotation
 		| ArrayAccess

+ 10 - 6
codegen.ml

@@ -89,17 +89,21 @@ let rec has_properties c =
 		match f.cf_kind with
 		| Var { v_read = AccCall } -> true
 		| Var { v_write = AccCall } -> true
+		| _ when Meta.has Meta.Accessor f.cf_meta -> true
 		| _ -> false
 	) c.cl_ordered_fields || (match c.cl_super with Some (c,_) -> has_properties c | _ -> false)
 
 let get_properties fields =
 	List.fold_left (fun acc f ->
-		let acc = (match f.cf_kind with
-		| Var { v_read = AccCall } -> ("get_" ^ f.cf_name , "get_" ^ f.cf_name) :: acc
-		| _ -> acc) in
-		match f.cf_kind with
-		| Var { v_write = AccCall } -> ("set_" ^ f.cf_name , "set_" ^ f.cf_name) :: acc
-		| _ -> acc
+		if Meta.has Meta.Accessor f.cf_meta then
+			(f.cf_name, f.cf_name) :: acc
+		else
+			let acc = (match f.cf_kind with
+			| Var { v_read = AccCall } -> ("get_" ^ f.cf_name , "get_" ^ f.cf_name) :: acc
+			| _ -> acc) in
+			match f.cf_kind with
+			| Var { v_write = AccCall } -> ("set_" ^ f.cf_name , "set_" ^ f.cf_name) :: acc
+			| _ -> acc
 	) [] fields
 
 let add_property_field com c =

+ 1 - 0
common.ml

@@ -320,6 +320,7 @@ module MetaInfo = struct
 	let to_string = function
 		| Abstract -> ":abstract",("Sets the underlying class implementation as 'abstract'",[Platforms [Java;Cs]])
 		| Access -> ":access",("Forces private access to package, type or field",[HasParam "Target path";UsedOnEither [TClass;TClassField]])
+		| Accessor -> ":accessor",("Used internally by DCE to mark property accessors",[UsedOn TClassField;Internal])
 		| Allow -> ":allow",("Allows private access from package, type or field",[HasParam "Target path";UsedOnEither [TClass;TClassField]])
 		| Annotation -> ":annotation",("Annotation (@interface) definitions on -java-lib imports will be annotated with this metadata. Has no effect on types compiled by Haxe",[Platform Java; UsedOn TClass])
 		| ArrayAccess -> ":arrayAccess",("Allows [] access on an abstract",[UsedOnEither [TAbstract;TAbstractField]])

+ 27 - 0
dce.ml

@@ -440,12 +440,38 @@ let run com main full =
 		| (TClassDecl c) as mt :: l when keep_whole_class dce c ->
 			loop (mt :: acc) l
 		| (TClassDecl c) as mt :: l ->
+			let check_property cf stat =
+				let add_accessor_metadata cf =
+					if not (Meta.has Meta.Accessor cf.cf_meta) then cf.cf_meta <- (Meta.Accessor,[],c.cl_pos) :: cf.cf_meta
+				in
+				begin match cf.cf_kind with
+				| Var {v_read = AccCall} ->
+					begin try
+						add_accessor_metadata (PMap.find ("get_" ^ cf.cf_name) (if stat then c.cl_statics else c.cl_fields))
+					with Not_found ->
+						()
+					end
+				| _ ->
+					()
+				end;
+				begin match cf.cf_kind with
+				| Var {v_write = AccCall} ->
+					begin try
+						add_accessor_metadata (PMap.find ("set_" ^ cf.cf_name) (if stat then c.cl_statics else c.cl_fields))
+					with Not_found ->
+						()
+					end
+				| _ ->
+					()
+				end;
+			in
 			(* add :keep so subsequent filter calls do not process class fields again *)
 			c.cl_meta <- (Meta.Keep,[],c.cl_pos) :: c.cl_meta;
  			c.cl_ordered_statics <- List.filter (fun cf ->
 				let b = keep_field dce cf in
 				if not b then begin
 					if dce.debug then print_endline ("[DCE] Removed field " ^ (s_type_path c.cl_path) ^ "." ^ (cf.cf_name));
+					check_property cf true;
 					c.cl_statics <- PMap.remove cf.cf_name c.cl_statics;
 				end;
 				b
@@ -454,6 +480,7 @@ let run com main full =
 				let b = keep_field dce cf in
 				if not b then begin
 					if dce.debug then print_endline ("[DCE] Removed field " ^ (s_type_path c.cl_path) ^ "." ^ (cf.cf_name));
+					check_property cf false;
 					c.cl_fields <- PMap.remove cf.cf_name c.cl_fields;
 				end;
 				b

+ 26 - 0
tests/unit/TestDCE.hx

@@ -116,6 +116,20 @@ class TestDCE extends Test {
 		nhf(bc, "get_x");
 	}
 	
+	public function testProperty2() {
+        var a = new RemovePropertyKeepAccessors();
+        a.test = 3;
+        eq(a.test, 3);
+        Reflect.setProperty(a, "test", 2);
+        eq(a.test, 2);
+		
+		var c = Type.resolveClass("unit.RemovePropertyKeepAccessors");
+		hf(c, "get_test");
+		hf(c, "set_test");
+		hf(c, "_test");
+		nhf(c, "test");
+	}
+	
 	public function testClasses() {
 		t(Type.resolveClass("unit.UsedConstructed") != null);
 		t(Type.resolveClass("unit.UsedReferenced") != null);
@@ -211,4 +225,16 @@ class InterfaceMethodFromBaseClassChild extends InterfaceMethodFromBaseClass imp
 class ThrownWithToString {
 	public function new() { }
 	public function toString() { return "I was thrown today"; }
+}
+
+
+class RemovePropertyKeepAccessors
+{
+    public function new() {}
+
+    var _test:Float;
+    public var test(get, set):Float;
+
+    public function get_test():Float return _test;
+    public function set_test(a:Float):Float { _test = a; return _test; }
 }