diff --git a/src/imports.jl b/src/imports.jl index 4fa76a94..9f5e9b52 100644 --- a/src/imports.jl +++ b/src/imports.jl @@ -84,6 +84,15 @@ function _mark_import_arg(arg, par, state, usinged) end end +function has_workspace_package(server, name) + haskey(server.workspacepackages, name) && + hasscope(getcst(server.workspacepackages[name])) && + haskey(scopeof(getcst(server.workspacepackages[name])).names, name) && + scopeof(getcst(server.workspacepackages[name])).names[name] isa Binding && + scopeof(getcst(server.workspacepackages[name])).names[name].val isa EXPR && + CSTParser.defines_module(scopeof(getcst(server.workspacepackages[name])).names[name].val) +end + function add_to_imported_modules(scope::Scope, name::Symbol, val) if scope.modules isa Dict scope.modules[name] = val @@ -112,6 +121,8 @@ function _get_field(par, arg, state) if par isa SymbolServer.EnvStore if (arg_scope = retrieve_scope(arg)) !== nothing && (tlm = get_named_toplevel_module(arg_scope, arg_str_rep)) !== nothing && hasbinding(tlm) return bindingof(tlm) + elseif has_workspace_package(state.server, arg_str_rep) + return scopeof(getcst(state.server.workspacepackages[arg_str_rep])).names[arg_str_rep] elseif haskey(par, Symbol(arg_str_rep)) if isempty(state.env.project_deps) || Symbol(arg_str_rep) in state.env.project_deps return par[Symbol(arg_str_rep)] diff --git a/src/server.jl b/src/server.jl index d056ceaf..80c7d29d 100644 --- a/src/server.jl +++ b/src/server.jl @@ -19,9 +19,11 @@ end mutable struct FileServer <: AbstractServer files::Dict{String,File} roots::Set{File} + workspacepackages::Dict{String,File} # list of files that may represent within-workspace packages external_env::ExternalEnv end -FileServer() = FileServer(Dict{String,File}(), Set{File}(), ExternalEnv(Dict{Symbol,SymbolServer.ModuleStore}(:Base => SymbolServer.stdlibs[:Base], :Core => SymbolServer.stdlibs[:Core]), SymbolServer.collect_extended_methods(SymbolServer.stdlibs), Symbol[])) +FileServer() = FileServer(Dict{String,File}(), Set{File}(), Dict{String,File}(), ExternalEnv(Dict{Symbol,SymbolServer.ModuleStore}(:Base => SymbolServer.stdlibs[:Base], :Core => SymbolServer.stdlibs[:Core]), SymbolServer.collect_extended_methods(SymbolServer.stdlibs), Symbol[])) + hasfile(server::FileServer, path::String) = haskey(server.files, path) canloadfile(server, path) = isfile(path) diff --git a/test/runtests.jl b/test/runtests.jl index 9caec8ce..50cfbacc 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1681,6 +1681,32 @@ end @test length(StaticLint.loose_refs(bindingof(cst[1][3][3][1]))) == 2 end +@testset "test workspace packages" begin + empty!(server.files) + s1 = """ + module WorkspaceMod + inner_sym = 1 + exported_sym = 1 + export exported_sym + end""" + f1 = StaticLint.File("workspacemod.jl", s1, CSTParser.parse(s1, true), nothing, server) + StaticLint.setroot(f1, f1) + StaticLint.setfile(server, f1.path, f1) + StaticLint.semantic_pass(f1) + server.workspacepackages["WorkspaceMod"] = f1 + s2 = """ + using WorkspaceMod + exported_sym + WorkspaceMod.inner_sym + """ + f2 = StaticLint.File("someotherfile.jl", s2, CSTParser.parse(s2, true), nothing, server) + StaticLint.setroot(f2, f2) + StaticLint.setfile(server, f2.path, f2) + StaticLint.semantic_pass(f2) + @test StaticLint.hasref(StaticLint.getcst(f2)[1][2][1]) + @test StaticLint.hasref(StaticLint.getcst(f2)[2]) + @test StaticLint.hasref(StaticLint.getcst(f2)[3][3][1]) +end @testset "#1218" begin cst = parse_and_pass("""function foo(a; p) a+p end foo(1, p = true)""")