Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions src/StaticLint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,11 @@ mutable struct Toplevel{T} <: State
env::ExternalEnv
server
flags::Int
forced_references::Set{String}
end

Toplevel(file, included_files, scope, in_modified_expr, modified_exprs, delayed, resolveonly, env, server) =
Toplevel(file, included_files, scope, in_modified_expr, modified_exprs, delayed, resolveonly, env, server, 0)
Toplevel(file, included_files, scope, in_modified_expr, modified_exprs, delayed, resolveonly, env, server, 0, Set{String}())

function (state::Toplevel)(x::EXPR)
resolve_import(x, state)
Expand Down Expand Up @@ -105,9 +106,10 @@ mutable struct Delayed <: State
env::ExternalEnv
server
flags::Int
forced_references::Set{String}
end

Delayed(scope, env, server) = Delayed(scope, env, server, 0)
Delayed(scope, env, server) = Delayed(scope, env, server, 0, Set{String}())

function (state::Delayed)(x::EXPR)
mark_bindings!(x, state)
Expand All @@ -134,8 +136,11 @@ mutable struct ResolveOnly <: State
scope::Scope
env::ExternalEnv
server
forced_references::Set{String}
end

ResolveOnly(scope,env,server) = ResolveOnly(scope,env,server,Set{String}())

function (state::ResolveOnly)(x::EXPR)
if hasscope(x)
s0 = state.scope
Expand Down Expand Up @@ -163,6 +168,26 @@ function flag!(state, x::EXPR)
return old
end

function add_forced_references!(file, current::Set{String})

if :_text_document in propertynames(file) # 1.56.2
source = file._text_document._content
elseif :_content in propertynames(file) # 1.38.2
source = file._content
elseif :source in propertynames(file)
source = file.source
else
source = ""
end

linter_rows = collect(eachmatch(r"(^|\n)#@linter_refs (?<refs>.*)", source))
for r in linter_rows
for ref in split(r[:refs], ","; keepempty=false)
push!(current, strip(ref))
end
end
end

"""
semantic_pass(file, modified_expr=nothing)

Expand All @@ -171,26 +196,30 @@ Performs a semantic pass across a project from the entry point `file`. A first p
function semantic_pass(file, modified_expr = nothing)
server = file.server
env = getenv(file, server)

forced_references = Set{String}()
add_forced_references!(file, forced_references)

setscope!(getcst(file), Scope(nothing, getcst(file), Dict(), Dict{Symbol,Any}(:Base => env.symbols[:Base], :Core => env.symbols[:Core]), nothing))
state = Toplevel(file, [getpath(file)], scopeof(getcst(file)), modified_expr === nothing, modified_expr, EXPR[], EXPR[], env, server)
state = Toplevel(file, [getpath(file)], scopeof(getcst(file)), modified_expr === nothing, modified_expr, EXPR[], EXPR[], env, server, 0, forced_references)
state(getcst(file))
for x in state.delayed
if hasscope(x)
traverse(x, Delayed(scopeof(x), env, server))
traverse(x, Delayed(scopeof(x), env, server, 0, state.forced_references))
for (k, b) in scopeof(x).names
infer_type_by_use(b, env)
check_unused_binding(b, scopeof(x))
end
else
traverse(x, Delayed(retrieve_delayed_scope(x), env, server))
traverse(x, Delayed(retrieve_delayed_scope(x), env, server, 0, state.forced_references))
end
end
if state.resolveonly !== nothing
for x in state.resolveonly
if hasscope(x)
traverse(x, ResolveOnly(scopeof(x), env, server))
traverse(x, ResolveOnly(scopeof(x), env, server, state.forced_references))
else
traverse(x, ResolveOnly(retrieve_delayed_scope(x), env, server))
traverse(x, ResolveOnly(retrieve_delayed_scope(x), env, server, state.forced_references))
end
end
end
Expand Down Expand Up @@ -331,6 +360,7 @@ function followinclude(x, state::State)
push!(state.included_files, getpath(state.file))
setroot(state.file, getroot(oldfile))
setscope!(getcst(state.file), nothing)
add_forced_references!(state.file, state.forced_references)
state(getcst(state.file))
state.file = oldfile
pop!(state.included_files)
Expand Down
6 changes: 6 additions & 0 deletions src/references.jl
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ function resolve_ref(x::EXPR, scope::Scope, state::State)::Bool
if !resolved && !CSTParser.defines_module(scope.expr) && parentof(scope) isa Scope
return resolve_ref(x, parentof(scope), state)
end

if valof(x) in state.forced_references
setref!(x, Binding(noname, nothing, nothing, []))
return true
end

return resolved
end

Expand Down