diff --git a/src/compiler/server/serverCache.ml b/src/compiler/server/serverCache.ml index fe010e25068..69ddd9ed582 100644 --- a/src/compiler/server/serverCache.ml +++ b/src/compiler/server/serverCache.ml @@ -438,7 +438,7 @@ let rec add_modules sctx com delay (m : module_def) (from_binary : bool) (p : po ) m.m_types; (* The main module gets added when reading hxb already, so let's not add it again. Note that we can't set its m_added ahead of time because we want the rest of the logic here to run. *) - if not from_binary || m != m then + if not from_binary then com.module_lut#add m.m_path m; handle_cache_bound_objects com m.m_extra.m_cache_bound_objects; let typing_mode = get_typing_mode com m.m_extra in diff --git a/src/context/display/displayFields.ml b/src/context/display/displayFields.ml index 8593d0e0551..1d84fae8019 100644 --- a/src/context/display/displayFields.ml +++ b/src/context/display/displayFields.ml @@ -256,7 +256,7 @@ let collect ctx e_ast e dk with_type p = PMap.mem field_name c.cl_fields || PMap.mem field_name c.cl_statics in PMap.foldi (fun name item acc -> - if (sl = [] || List.mem name sl && is_new_item acc name) && not (abstract_has_own_field name) then + if (sl = [] || List.mem name sl) && is_new_item acc name && not (abstract_has_own_field name) then PMap.add name item acc else acc diff --git a/src/context/display/displayToplevel.ml b/src/context/display/displayToplevel.ml index e87eaadaa60..e89b92b8a93 100644 --- a/src/context/display/displayToplevel.ml +++ b/src/context/display/displayToplevel.ml @@ -39,7 +39,7 @@ let perform_type_voodoo t tl' tr' = | _ -> (List.rev acc) @ tl' in let tl = loop [] tl tl' in - TFun(tl,if tr == t_dynamic then tr' else tr') + TFun(tl,if tr == t_dynamic then tr' else tr) | _ -> TFun(tl',tr') @@ -89,7 +89,8 @@ class explore_class_path_task com checked recursive f_pack f_module dir pack = o let name = String.sub file 0 (l - 3) in try let dot_pos = String.rindex name '.' in - let second_ext = String.sub file dot_pos (String.length name - dot_pos) in + (* The second extension without the dot, e.g. "js" for Foo.js.hx. *) + let second_ext = String.sub file (dot_pos + 1) (String.length name - dot_pos - 1) in if (Option.map_default (fun custom_ext -> custom_ext = second_ext) false com.custom_ext) || platform_str = second_ext then String.sub file 0 dot_pos else diff --git a/tests/server/src/cases/ServerTests.hx b/tests/server/src/cases/ServerTests.hx index 96437dd227c..fc8ed1d89f2 100644 --- a/tests/server/src/cases/ServerTests.hx +++ b/tests/server/src/cases/ServerTests.hx @@ -503,6 +503,37 @@ class ServerTests extends TestCase { }); } + function testSyntaxCachePlatformSpecificFiles() { + vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); + vfs.putContent("EmptyJs.js.hx", "class EmptyJs {}"); + vfs.putContent("EmptyPy.py.hx", "class EmptyPy {}"); + var args = ["-cp", ".", "-js", "no.js", "--no-output"]; + runHaxeJson(args, ServerMethods.ReadClassPaths, {wait: true}); + var completion = runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); + // EmptyJs.js.hx matches the current platform and must show up as module EmptyJs + assertHasCompletion(completion, module -> switch (module.kind) { + case Type: module.args.path.typeName == "EmptyJs"; + case _: false; + }); + // EmptyPy.py.hx belongs to another platform and must not show up + assertHasNoCompletion(completion, module -> switch (module.kind) { + case Type: module.args.path.typeName == "EmptyPy"; + case _: false; + }); + } + + function testSyntaxCacheCustomExtensionFiles() { + vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); + vfs.putContent("EmptyCustom.custom.hx", "class EmptyCustom {}"); + var args = ["-cp", ".", "--custom-extension", "custom", "--interp"]; + runHaxeJson(args, ServerMethods.ReadClassPaths, {wait: true}); + var completion = runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); + assertHasCompletion(completion, module -> switch (module.kind) { + case Type: module.args.path.typeName == "EmptyCustom"; + case _: false; + }); + } + function testVectorInliner() { vfs.putContent("Vector.hx", getTemplate("Vector.hx")); vfs.putContent("VectorInliner.hx", getTemplate("VectorInliner.hx")); diff --git a/tests/server/src/cases/display/Toplevel.hx b/tests/server/src/cases/display/Toplevel.hx index 706d0ec1c0f..50ad9d64adc 100644 --- a/tests/server/src/cases/display/Toplevel.hx +++ b/tests/server/src/cases/display/Toplevel.hx @@ -322,6 +322,21 @@ class Toplevel extends DisplayTestCase { eq(true, hasToplevel(f, "local", "foo")); } + /** + class Main { + macro static function mac():haxe.macro.Expr.ExprOf { + return macro ""; + } + static function main() { + {-1-} + } + } + **/ + function testMacroFieldCallSiteType(_) { + // the merged macro/non-macro type must keep the non-macro (call site) return type (ExprOf -> String) + eq(true, hasToplevel(toplevel(1), "static", "mac", "() -> String")); + } + /** class C1 { public function f1(t:T) { }