diff --git a/src/StaticLint.jl b/src/StaticLint.jl index b9e082ef..fd80386d 100644 --- a/src/StaticLint.jl +++ b/src/StaticLint.jl @@ -45,6 +45,7 @@ bindingof(m::Meta) = m.binding mutable struct State{T} file::T targetfile::Union{Nothing,T} + included_files::Vector{String} scope::Scope delayed::Bool urefs::Vector{EXPR} @@ -140,12 +141,18 @@ function followinclude(x, state::State) path = "" end if !isempty(path) + if path in state.included_files + seterror!(x, IncludeLoop) + return + end oldfile = state.file state.file = getfile(state.server, path) + push!(state.included_files, getpath(state.file)) setroot(state.file, getroot(oldfile)) setscope!(getcst(state.file), nothing) state(getcst(state.file)) state.file = oldfile + pop!(state.included_files) else seterror!(x, MissingFile) end diff --git a/src/linting/checks.jl b/src/linting/checks.jl index 042d52c5..1a13c122 100644 --- a/src/linting/checks.jl +++ b/src/linting/checks.jl @@ -9,8 +9,10 @@ PointlessOR, PointlessAND, UnusedBinding, InvalidTypeDeclaration, +IncludeLoop, MissingFile) + const LintCodeDescriptions = Dict{LintCodes,String}( IncorrectCallNargs => "An incorrect number of function arguments has been passed.", IncorrectIterSpec => "A loop iterator has been used that will likely error.", @@ -21,6 +23,7 @@ const LintCodeDescriptions = Dict{LintCodes,String}( PointlessAND => "The first argument of a `&&` call is `false`.", UnusedBinding => "The variable name has been bound but not used.", InvalidTypeDeclaration => "A non-DataType has been used in a type declaration statement.", + IncludeLoop => "Loop detected, this file has already been included.", MissingFile => "The included file can not be found." ) diff --git a/src/server.jl b/src/server.jl index 3a5a00a4..446b56b5 100644 --- a/src/server.jl +++ b/src/server.jl @@ -39,7 +39,7 @@ getsymbolserver(server::FileServer) = server.symbolserver function scopepass(file, target = nothing) server = file.server setscope!(getcst(file), Scope(nothing, getcst(file), Dict(), Dict{String,Any}("Base" => getsymbolserver(server)["Base"], "Core" => getsymbolserver(server)["Core"]), false)) - state = State(file, target, scopeof(getcst(file)), false, EXPR[], server) + state = State(file, target, [getpath(file)], scopeof(getcst(file)), false, EXPR[], server) state(getcst(file)) for uref in state.urefs s = retrieve_delayed_scope(uref)