소스 검색

[macro] do not use dependency file as file for macro created modules (#11702)

* [tests] add test for 11702

* [macro] do not use dependency file as file for macro created modules

* Use unique file names
Rudy Ges 1 년 전
부모
커밋
3b36da4e21

+ 7 - 0
src/context/common.ml

@@ -230,6 +230,13 @@ class file_keys = object(self)
 			let key = Path.UniqueKey.create file in
 			Hashtbl.add cache file key;
 			key
+
+	val virtual_counter = ref 0
+
+	method generate_virtual step =
+		incr virtual_counter;
+		Printf.sprintf "file_%i_%i" step !virtual_counter
+
 end
 
 type shared_display_information = {

+ 2 - 2
src/typing/macroContext.ml

@@ -476,7 +476,7 @@ let make_macro_api ctx mctx p =
 			in
 			let add is_macro ctx =
 				let mdep = Option.map_default (fun s -> TypeloadModule.load_module ~origin:MDepFromMacro ctx (parse_path s) pos) ctx.m.curmod mdep in
-				let mnew = TypeloadModule.type_module ctx.com ctx.g ~dont_check_path:(has_native_meta) m (Path.UniqueKey.lazy_path mdep.m_extra.m_file) [tdef,pos] pos in
+				let mnew = TypeloadModule.type_module ctx.com ctx.g ~dont_check_path:(has_native_meta) m (ctx.com.file_keys#generate_virtual ctx.com.compilation_step) [tdef,pos] pos in
 				mnew.m_extra.m_kind <- if is_macro then MMacro else MFake;
 				add_dependency mnew mdep MDepFromMacro;
 				ctx.com.module_nonexistent_lut#clear;
@@ -506,7 +506,7 @@ let make_macro_api ctx mctx p =
 				let m = ctx.com.module_lut#find mpath in
 				ignore(TypeloadModule.type_types_into_module ctx.com ctx.g m types pos)
 			with Not_found ->
-				let mnew = TypeloadModule.type_module ctx.com ctx.g mpath (Path.UniqueKey.lazy_path ctx.m.curmod.m_extra.m_file) types pos in
+				let mnew = TypeloadModule.type_module ctx.com ctx.g mpath (ctx.com.file_keys#generate_virtual ctx.com.compilation_step) types pos in
 				mnew.m_extra.m_kind <- MFake;
 				add_dependency mnew ctx.m.curmod MDepFromMacro;
 				ctx.com.module_nonexistent_lut#clear;

+ 30 - 0
tests/server/src/cases/issues/Issue11702.hx

@@ -0,0 +1,30 @@
+package cases.issues;
+
+import haxe.display.Diagnostic;
+
+class Issue11702 extends TestCase {
+	function test(_) {
+		vfs.putContent("Main.hx", getTemplate("issues/Issue11702/Main.hx"));
+		vfs.putContent("Foo.hx", getTemplate("issues/Issue11702/Foo.hx"));
+		vfs.putContent("Bar.hx", getTemplate("issues/Issue11702/Bar.hx"));
+		vfs.putContent("Proxy.hx", getTemplate("issues/Issue11702/Proxy.hx"));
+		vfs.putContent("State.hx", getTemplate("issues/Issue11702/State.hx"));
+		vfs.putContent("Macro.macro.hx", getTemplate("issues/Issue11702/Macro.hx"));
+
+		var args = ["-main", "Main"];
+		runHaxe(args);
+		assertSuccess();
+
+		var content = getTemplate("issues/Issue11702/Foo2.hx");
+		var transform = Markers.parse(content);
+		vfs.putContent("Foo.hx", transform.source);
+
+		var foo = new FsPath("Foo.hx");
+		runHaxeJson(args, ServerMethods.Invalidate, {file: foo});
+
+		runHaxeJsonCb(args, DisplayMethods.Hover, {file: foo, offset: transform.offset(1)}, res -> {
+			Assert.equals("Main", res.item.args.path.moduleName);
+		});
+		assertSuccess();
+	}
+}

+ 5 - 0
tests/server/test/templates/issues/Issue11702/Bar.hx

@@ -0,0 +1,5 @@
+class Bar {
+	static function bar() {
+		var data:Proxy<Foo.FooData>;
+	}
+}

+ 7 - 0
tests/server/test/templates/issues/Issue11702/Foo.hx

@@ -0,0 +1,7 @@
+class Foo extends State {
+	public var data:FooData;
+}
+
+typedef FooData = {
+	foo:String
+}

+ 11 - 0
tests/server/test/templates/issues/Issue11702/Foo2.hx

@@ -0,0 +1,11 @@
+class Foo extends State {
+	public var data:FooData;
+
+	public static function test() {
+		Ma{-1-}in;
+	}
+}
+
+typedef FooData = {
+	foo:String
+}

+ 80 - 0
tests/server/test/templates/issues/Issue11702/Macro.hx

@@ -0,0 +1,80 @@
+import haxe.macro.Context;
+import haxe.macro.Expr;
+import haxe.macro.TypeTools;
+
+class Macro {
+	@:persistent static var generated = new Map<String, Bool>();
+
+	static function isAlive(ct:ComplexType, pos:Position):Bool {
+		// Null check is just there to make it a one liner
+		// Basically returning true if no exception is caught
+		return try Context.resolveType(ct, pos) != null catch(e) false;
+	}
+
+	public static function buildState() {
+		var constructor = [];
+		var fields = Context.getBuildFields().map(f -> {
+			return switch f.kind {
+				case _ if (f.access.contains(AStatic)): f;
+
+				case FVar(null, _): f;
+				case FVar(ct, e):
+					var fname = f.name;
+					constructor.push(macro this.$fname = new Proxy<$ct>(null));
+
+					{
+						name: f.name,
+						doc: f.doc,
+						pos: f.pos,
+						meta: f.meta,
+						access: f.access,
+						kind: FieldType.FVar(macro :Proxy<$ct>, e)
+					};
+
+				case FProp(_) | FFun(_): f;
+			}
+		});
+
+		if (constructor.length > 0) {
+			fields.push({
+				name: "new",
+				doc: null,
+				pos: Context.currentPos(),
+				meta: [],
+				access: [APublic],
+				kind: FFun({
+					args: [],
+					ret: null,
+					params: null,
+					expr: macro $b{constructor}
+				})
+			});
+		}
+
+		return fields;
+	}
+
+	public static function buildProxy() {
+		switch (Context.getLocalType()) {
+			case TInst(_, [target]):
+				var pos = Context.currentPos();
+				var targetCt = TypeTools.toComplexType(target);
+				var bt = TypeTools.toBaseType(target);
+				var key = ["Proxy", bt.module, bt.name].join("__");
+				var ct = TPath({pack: [], name: key});
+				if (generated.exists(key) && isAlive(ct, pos)) return ct;
+
+				var genDef = macro class $key {
+					var data:$targetCt;
+					public function new(data:$targetCt) this.data = data;
+					public inline function get():$targetCt return data;
+				};
+
+				Context.defineType(genDef);
+				generated.set(key, true);
+				return ct;
+
+			case _: throw "";
+		}
+	}
+}

+ 9 - 0
tests/server/test/templates/issues/Issue11702/Main.hx

@@ -0,0 +1,9 @@
+import Foo;
+
+class Main {
+	public static function main() {}
+
+	static function foo() {
+		var bar:Bar;
+	}
+}

+ 2 - 0
tests/server/test/templates/issues/Issue11702/Proxy.hx

@@ -0,0 +1,2 @@
+@:genericBuild(Macro.buildProxy())
+class Proxy<T> {}

+ 2 - 0
tests/server/test/templates/issues/Issue11702/State.hx

@@ -0,0 +1,2 @@
+@:autoBuild(Macro.buildState())
+class State {}