Skip to content

Commit 7b5e33b

Browse files
authored
Merge pull request #290 from julia-vscode/sp/no-macrocall-linting
disable non-at-eval macrocall linting
2 parents 5afcec0 + 13b337d commit 7b5e33b

File tree

3 files changed

+26
-6
lines changed

3 files changed

+26
-6
lines changed

src/bindings.jl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ function mark_bindings!(x::EXPR, state)
5959
mark_sig_args!(x.args[1])
6060
elseif CSTParser.iscurly(x.args[1])
6161
mark_typealias_bindings!(x)
62+
elseif is_in_noneval_macrocall(x.args[1])
63+
return
6264
elseif !is_getfield(x.args[1])
6365
mark_binding!(x.args[1], x)
6466
end
@@ -156,8 +158,8 @@ function mark_parameters(sig::EXPR, params = String[])
156158
for i = 2:length(sig.args)
157159
x = mark_binding!(sig.args[i])
158160
if bindingof(x) isa Binding && valof(bindingof(x).name) in params
159-
# Don't mark a new binding if a parameter has already been
160-
# introduced from a :where
161+
# Don't mark a new binding if a parameter has already been
162+
# introduced from a :where
161163
x.meta.binding = nothing
162164
end
163165
end
@@ -259,7 +261,7 @@ end
259261
260262
Add the binding of `x` to the current scope. Special handling is required for:
261263
* macros: to prefix the `@`
262-
* functions: These are added to the top-level scope unless this syntax is used to define a closure within a function. If a function with the same name already exists in the scope then it is not replaced. This enables the `refs` list of the Binding of that 'root method' to hold a method table, the name of the new function will resolve to the binding of the root method (to get a list of actual methods -`[get_method(ref) for ref in binding.refs if get_method(ref) !== nothing]`). For example
264+
* functions: These are added to the top-level scope unless this syntax is used to define a closure within a function. If a function with the same name already exists in the scope then it is not replaced. This enables the `refs` list of the Binding of that 'root method' to hold a method table, the name of the new function will resolve to the binding of the root method (to get a list of actual methods -`[get_method(ref) for ref in binding.refs if get_method(ref) !== nothing]`). For example
263265
```julia
264266
[1] f() = 1
265267
[2] f(x) = 2
@@ -302,14 +304,14 @@ function add_binding(x, state, scope=state.scope)
302304
# Overloading
303305
if haskey(tls.names, name) && eventually_overloads(tls.names[name], lhs_ref.vals[Symbol(name)], state)
304306
# Though we're explicitly naming a function for overloading, it has already been imported to the toplevel scope.
305-
if !hasref(b.name)
307+
if !hasref(b.name)
306308
setref!(b.name, tls.names[name]) # Add ref to previous overload
307309
overload_method(tls, b, VarRef(lhs_ref.name, Symbol(name)))
308310
end
309311
# Do nothing, get_name(x) will resolve to the root method
310312
elseif isexportedby(name, lhs_ref)
311313
# Name is already available
312-
tls.names[name] = b
314+
tls.names[name] = b
313315
if !hasref(b.name) # Is this an appropriate indicator that we've not marked the overload?
314316
push!(b.refs, maybe_lookup(lhs_ref[Symbol(name)], state))
315317
setref!(b.name, b) # we actually set the rhs of the qualified name to point to this binding

src/linting/checks.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,8 @@ function collect_hints(x::EXPR, env, missingrefs=:all, isquoted=false, errs=Tupl
554554
elseif !isquoted
555555
if missingrefs != :none && isidentifier(x) && !hasref(x) &&
556556
!(valof(x) == "var" && parentof(x) isa EXPR && isnonstdid(parentof(x))) &&
557-
!((valof(x) == "stdcall" || valof(x) == "cdecl" || valof(x) == "fastcall" || valof(x) == "thiscall" || valof(x) == "llvmcall") && is_in_fexpr(x, x -> iscall(x) && isidentifier(x.args[1]) && valof(x.args[1]) == "ccall"))
557+
!((valof(x) == "stdcall" || valof(x) == "cdecl" || valof(x) == "fastcall" || valof(x) == "thiscall" || valof(x) == "llvmcall") && is_in_fexpr(x, x -> iscall(x) && isidentifier(x.args[1]) && valof(x.args[1]) == "ccall")) &&
558+
!is_in_noneval_macrocall(x)
558559

559560
push!(errs, (pos, x))
560561
elseif haserror(x) && errorof(x) isa StaticLint.LintCodes
@@ -904,6 +905,12 @@ function is_sig_arg(x)
904905
is_in_fexpr(x, CSTParser.iscall)
905906
end
906907

908+
function is_in_noneval_macrocall(x)
909+
macrocall = maybe_get_parent_fexpr(x, x -> x.head === :macrocall && valof(x.args[1]) != "@eval")
910+
return macrocall !== nothing
911+
end
912+
913+
907914
function is_overwritten_in_loop(x)
908915
# Cuts out false positives for check_unused_binding - the linear nature of our
909916
# semantic passes mean a variable declared at the end of a loop's block but used at

test/runtests.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,3 +1744,14 @@ end
17441744
@test isempty(StaticLint.collect_hints(cst, server))
17451745

17461746
end
1747+
1748+
1749+
@testset "macrocall bindings: #2187" begin
1750+
cst = parse_and_pass("""
1751+
function f()
1752+
@info "Downloading" source = url dest = file
1753+
return nothing
1754+
end
1755+
""")
1756+
@test isempty(StaticLint.collect_hints(cst, server))
1757+
end

0 commit comments

Comments
 (0)