@@ -74,124 +74,10 @@
Loading
74 74
    end
75 75
    doc._version = params.textDocument.version
76 76
77 -
    if length(params.contentChanges) == 1 && !endswith(doc._uri, ".jmd") && !ismissing(first(params.contentChanges).range)
78 -
        tdcce = first(params.contentChanges)
79 -
        new_cst = _partial_update(doc, tdcce)
80 -
        scopepass(getroot(doc), doc)
81 -
        lint!(doc, server)
82 -
    else
83 -
        for tdcce in params.contentChanges
84 -
            applytextdocumentchanges(doc, tdcce)
85 -
        end
86 -
        parse_all(doc, server)
87 -
    end
88 -
end
89 -
90 -
function _partial_update(doc::Document, tdcce::TextDocumentContentChangeEvent)
91 -
    cst = getcst(doc)
92 -
    insert_range = get_offset(doc, tdcce.range)
93 -
94 -
    applytextdocumentchanges(doc, tdcce)
95 -
96 -
    updated_text = get_text(doc)
97 -
98 -
    i1, i2, loc1, loc2 = get_update_area(cst, insert_range)
99 -
    is = insert_size(tdcce.text, insert_range)
100 -
    if isempty(updated_text)
101 -
        empty!(cst.args)
102 -
        StaticLint.clear_meta(cst)
103 -
        cst.span = cst.fullspan = 0
104 -
    elseif 0 < i1 <= i2
105 -
        old_span = cst_len(cst, i1, i2)
106 -
        ps = ParseState(updated_text, loc1)
107 -
        args = EXPR[]
108 -
        if i1 == 1 && (ps.nt.kind == CSTParser.Tokens.WHITESPACE || ps.nt.kind == CSTParser.Tokens.COMMENT)
109 -
            CSTParser.next(ps)
110 -
            push!(args, CSTParser.mLITERAL(ps.nt.startbyte, ps.nt.startbyte, "", Tokens.NOTHING))
111 -
        else
112 -
            push!(args, CSTParser.parse(ps)[1])
113 -
        end
114 -
        prev_pos = -1
115 -
        while ps.nt.startbyte < old_span + loc1 + is && !(ps.done || kindof(ps.nt) === CSTParser.Tokens.ENDMARKER)
116 -
            if ps.nt.startbyte <= prev_pos
117 -
                throw(LSInfiniteLoop("Loop not progressing as it should."))
118 -
            else
119 -
                prev_pos = ps.nt.startbyte
120 -
            end
121 -
            push!(args, CSTParser.parse(ps)[1])
122 -
        end
123 -
        new_span = 0
124 -
        for i = 1:length(args)
125 -
            new_span += args[i].fullspan
126 -
        end
127 -
        # remove old blocks
128 -
        while old_span + is < new_span && i2 < length(cst.args)
129 -
            i2 += 1
130 -
            old_span += cst.args[i2].fullspan
131 -
        end
132 -
        for i = i1:i2
133 -
            StaticLint.clear_meta(cst.args[i])
134 -
        end
135 -
        deleteat!(cst.args, i1:i2)
136 -
137 -
        # insert new blocks
138 -
        for a in args
139 -
            insert!(cst.args, i1, a)
140 -
            CSTParser.setparent!(cst.args[i1], cst)
141 -
            i1 += 1
142 -
        end
143 -
    else
144 -
        StaticLint.clear_meta(cst)
145 -
        cst = CSTParser.parse(updated_text, true)
77 +
    for tdcce in params.contentChanges
78 +
        applytextdocumentchanges(doc, tdcce)
146 79
    end
147 -
    CSTParser.update_span!(cst)
148 -
    doc.cst = cst
149 -
    if typof(doc.cst) === CSTParser.FileH
150 -
        doc.cst.val = getpath(doc)
151 -
        set_doc(doc.cst, doc)
152 -
    end
153 -
end
154 -
155 -
insert_size(inserttext, insertrange) = sizeof(inserttext) - max(last(insertrange) - first(insertrange), 0) # OK, used to adjust EXPR spans
156 -
157 -
function cst_len(x, i1=1, i2=length(x.args))
158 -
    n = 0
159 -
    @inbounds for i = i1:i2
160 -
        n += x.args[i].fullspan
161 -
    end
162 -
    n
163 -
end
164 -
165 -
function get_update_area(cst, insert_range)
166 -
    loc1 = loc2 = 0
167 -
    i1 = i2 = 0
168 -
169 -
    while i1 < length(cst.args)
170 -
        i1 += 1
171 -
        a = cst.args[i1]
172 -
        if loc1 <= first(insert_range) <= loc1 + a.fullspan
173 -
            loc2 = loc1
174 -
            i2 = i1
175 -
            if !(loc1 <= last(insert_range) <= loc1 + a.fullspan)
176 -
                while i2 < length(cst.args)
177 -
                    i2 += 1
178 -
                    a = cst.args[i2]
179 -
                    if loc2 <= last(insert_range) <= loc2 + a.fullspan
180 -
                        if i2 < length(cst.args) && last(insert_range) <= loc2 + a.fullspan
181 -
                            i2 += 1
182 -
                        end
183 -
                        break
184 -
                    end
185 -
                    loc2 += a.fullspan
186 -
                end
187 -
            elseif i2 < length(cst.args) && last(insert_range) == loc1 + a.fullspan
188 -
                i2 += 1
189 -
            end
190 -
            break
191 -
        end
192 -
        loc1 += a.fullspan
193 -
    end
194 -
    return i1, i2, loc1, loc2
80 +
    parse_all(doc, server)
195 81
end
196 82
197 83
function convert_lsrange_to_jlrange(doc::Document, range::Range)
@@ -212,11 +98,8 @@
Loading
212 98
        set_text!(doc, tdcce.text)
213 99
    else
214 100
        editrange = convert_lsrange_to_jlrange(doc, tdcce.range)
215 -
216 101
        text = get_text(doc)
217 -
218 102
        new_text = string(text[1:prevind(text, editrange.start)], tdcce.text, text[nextind(text, editrange.stop):lastindex(text)])
219 -
220 103
        set_text!(doc, new_text)
221 104
    end
222 105
end
@@ -229,12 +112,12 @@
Loading
229 112
    else
230 113
        doc.cst, ps = CSTParser.parse(ps, true)
231 114
    end
232 -
    if typof(doc.cst) === CSTParser.FileH
115 +
    if headof(doc.cst) === :file
233 116
        doc.cst.val = getpath(doc)
234 117
        set_doc(doc.cst, doc)
235 118
    end
119 +
    semantic_pass(getroot(doc), doc)
236 120
237 -
    scopepass(getroot(doc), doc)
238 121
    lint!(doc, server)
239 122
end
240 123
@@ -270,8 +153,7 @@
Loading
270 153
                    r[2] = char
271 154
                    offset += errs[i][2].span
272 155
                else
273 -
                    DiagnosticSeverities
274 -
                    if typof(errs[i][2]) === CSTParser.ErrorToken
156 +
                    if headof(errs[i][2]) === :errortoken
275 157
                        push!(out, Diagnostic(Range(r[1] - 1, r[2], line - 1, char), DiagnosticSeverities.Error, "Julia", "Julia", "Parsing error", missing, missing))
276 158
                    elseif CSTParser.isidentifier(errs[i][2]) && !StaticLint.haserror(errs[i][2])
277 159
                        push!(out, Diagnostic(Range(r[1] - 1, r[2], line - 1, char), DiagnosticSeverities.Warning, "Julia", "Julia", "Missing reference: $(errs[i][2].val)", missing, missing))
@@ -346,14 +228,15 @@
Loading
346 228
            push!(blocks, (ps.t.startbyte, CSTParser.INSTANCE(ps)))
347 229
        end
348 230
    end
349 -
    top = EXPR(CSTParser.FileH, EXPR[])
231 +
    top = EXPR(:file, EXPR[], nothing)
350 232
    if isempty(blocks)
351 233
        return top, ps
352 234
    end
353 235
354 236
    for (startbyte, b) in blocks
355 -
        if typof(b) === CSTParser.LITERAL && kindof(b) == CSTParser.Tokens.TRIPLE_CMD && (startswith(b.val, "julia") || startswith(b.val, "{julia"))
356 -
            blockstr = b.val
237 +
        if CSTParser.ismacrocall(b) && headof(b.args[1]) === :globalrefcmd && headof(b.args[3]) === :TRIPLESTRING && (startswith(b.args[3].val, "julia") || startswith(b.args[3].val, "{julia"))
238 +
            
239 +
            blockstr = b.args[3].val
357 240
            ps = CSTParser.ParseState(blockstr)
358 241
            # skip first line
359 242
            while ps.nt.startpos[1] == 1
@@ -361,18 +244,18 @@
Loading
361 244
            end
362 245
            prec_str_size = currentbyte:startbyte + ps.nt.startbyte + 3
363 246
364 -
            push!(top.args, CSTParser.mLITERAL(length(prec_str_size), length(prec_str_size), "", CSTParser.Tokens.STRING))
247 +
            push!(top.args, EXPR(:STRING, length(prec_str_size), length(prec_str_size)))
365 248
366 249
            args, ps = CSTParser.parse(ps, true)
367 250
            append!(top.args, args.args)
368 251
            CSTParser.update_span!(top)
369 252
            currentbyte = top.fullspan + 1
370 -
        elseif typof(b) === CSTParser.LITERAL && kindof(b) == CSTParser.Tokens.CMD && startswith(b.val, "j ")
371 -
            blockstr = b.val
253 +
        elseif CSTParser.ismacrocall(b) && headof(b.args[1]) === :globalrefcmd && headof(b.args[3]) === :STRING && startswith(b.val, "j ")
254 +
            blockstr = b.args[3].val
372 255
            ps = CSTParser.ParseState(blockstr)
373 256
            CSTParser.next(ps)
374 257
            prec_str_size = currentbyte:startbyte + ps.nt.startbyte + 1
375 -
            push!(top.args, CSTParser.mLITERAL(length(prec_str_size), length(prec_str_size), "", CSTParser.Tokens.STRING))
258 +
            push!(top.args, EXPR(:STRING, length(prec_str_size), length(prec_str_size)))
376 259
377 260
            args, ps = CSTParser.parse(ps, true)
378 261
            append!(top.args, args.args)
@@ -382,7 +265,7 @@
Loading
382 265
    end
383 266
384 267
    prec_str_size = currentbyte:sizeof(str) # OK
385 -
    push!(top.args, CSTParser.mLITERAL(length(prec_str_size), length(prec_str_size), "", CSTParser.Tokens.STRING))
268 +
    push!(top.args, EXPR(:STRING, length(prec_str_size), length(prec_str_size)))
386 269
387 270
    return top, ps
388 271
end
@@ -434,20 +317,20 @@
Loading
434 317
        pdoc = Document(puri, content, false, server)
435 318
        setdocument!(server, URI2(puri), pdoc)
436 319
        CSTParser.parse(get_text(pdoc), true)
437 -
        if typof(pdoc.cst) === CSTParser.FileH
320 +
        if headof(pdoc.cst) === :file
438 321
            pdoc.cst.val = getpath(pdoc)
439 322
            set_doc(pdoc.cst, pdoc)
440 323
        end
441 324
    else
442 325
        pdoc = getdocument(server, URI2(puri))
443 326
    end
444 -
    scopepass(getroot(pdoc), pdoc)
327 +
    semantic_pass(getroot(pdoc), pdoc)
445 328
    # check whether child has been included automatically
446 329
    if any(getpath(d) == child_path for (k, d) in getdocuments_pair(server) if !(k in previous_server_docs))
447 330
        cdoc = getdocument(server, URI2(filepath2uri(child_path)))
448 331
        parse_all(cdoc, server)
449 -
        scopepass(getroot(cdoc))
450 -
        return true
332 +
        semantic_pass(getroot(cdoc))
333 +
        return true, "", CSTParser.Tokens.STRING
451 334
    else
452 335
        # clean up
453 336
        foreach(k -> !(k in previous_server_docs) && deletedocument!(server, k), getdocuments_key(server))

@@ -181,8 +181,8 @@
Loading
181 181
    if pos > offset
182 182
        return nothing
183 183
    end
184 -
    if x.args !== nothing && typof(x) !== CSTParser.NONSTDIDENTIFIER
185 -
        for a in x.args
184 +
    if length(x) > 0 && headof(x) !== :NONSTDIDENTIFIER
185 +
        for a in x
186 186
            if pos < offset <= (pos + a.fullspan)
187 187
                return get_expr(a, offset, pos, ignorewhitespace)
188 188
            end
@@ -200,8 +200,8 @@
Loading
200 200
    if all(pos .> offset)
201 201
        return nothing
202 202
    end
203 -
    if x.args !== nothing && typof(x) !== CSTParser.NONSTDIDENTIFIER
204 -
        for a in x.args
203 +
    if length(x) > 0 && headof(x) !== :NONSTDIDENTIFIER
204 +
        for a in x
205 205
            if all(pos .< offset .<= (pos + a.fullspan))
206 206
                return get_expr(a, offset, pos, ignorewhitespace)
207 207
            end
@@ -221,35 +221,35 @@
Loading
221 221
end
222 222
223 223
function get_expr1(x, offset, pos=0)
224 -
    if x.args === nothing || isempty(x.args) || typof(x) === CSTParser.NONSTDIDENTIFIER
224 +
    if length(x) == 0 || headof(x) === :NONSTDIDENTIFIER
225 225
        if pos <= offset <= pos + x.span
226 226
            return x
227 227
        else
228 228
            return nothing
229 229
        end
230 230
    else
231 -
        for i = 1:length(x.args)
232 -
            arg = x.args[i]
231 +
        for i = 1:length(x)
232 +
            arg = x[i]
233 233
            if pos < offset < (pos + arg.span) # def within span
234 234
                return get_expr1(arg, offset, pos)
235 235
            elseif arg.span == arg.fullspan
236 236
                if offset == pos
237 237
                    if i == 1
238 238
                        return get_expr1(arg, offset, pos)
239 -
                    elseif CSTParser.typof(x.args[i - 1]) === CSTParser.IDENTIFIER
240 -
                        return get_expr1(x.args[i - 1], offset, pos)
239 +
                    elseif headof(x[i - 1]) === :IDENTIFIER
240 +
                        return get_expr1(x[i - 1], offset, pos)
241 241
                    else
242 242
                        return get_expr1(arg, offset, pos)
243 243
                    end
244 -
                elseif i == length(x.args) # offset == pos + arg.fullspan
244 +
                elseif i == length(x) # offset == pos + arg.fullspan
245 245
                    return get_expr1(arg, offset, pos)
246 246
                end
247 247
            else
248 248
                if offset == pos
249 249
                    if i == 1
250 250
                        return get_expr1(arg, offset, pos)
251 -
                    elseif CSTParser.typof(x.args[i - 1]) === CSTParser.IDENTIFIER
252 -
                        return get_expr1(x.args[i - 1], offset, pos)
251 +
                    elseif headof(x[i - 1]) === :IDENTIFIER
252 +
                        return get_expr1(x[i - 1], offset, pos)
253 253
                    else
254 254
                        return get_expr1(arg, offset, pos)
255 255
                    end
@@ -271,18 +271,69 @@
Loading
271 271
    if pos > offset
272 272
        return nothing
273 273
    end
274 -
    if x.args !== nothing
275 -
        for a in x.args
274 +
    if length(x) > 0
275 +
        for a in x
276 276
            if pos <= offset <= (pos + a.span)
277 277
                return get_identifier(a, offset, pos)
278 278
            end
279 279
            pos += a.fullspan
280 280
        end
281 -
    elseif typof(x) === CSTParser.IDENTIFIER && (pos <= offset <= (pos + x.span)) || pos == 0
281 +
    elseif headof(x) === :IDENTIFIER && (pos <= offset <= (pos + x.span)) || pos == 0
282 282
        return x
283 283
    end
284 284
end
285 285
286 +
287 +
if VERSION < v"1.1" || Sys.iswindows() && VERSION < v"1.3"
288 +
    _splitdir_nodrive(path::String) = _splitdir_nodrive("", path)
289 +
    function _splitdir_nodrive(a::String, b::String)
290 +
        m = match(Base.Filesystem.path_dir_splitter, b)
291 +
        m === nothing && return (a, b)
292 +
        a = string(a, isempty(m.captures[1]) ? m.captures[2][1] : m.captures[1])
293 +
        a, String(m.captures[3])
294 +
    end
295 +
    splitpath(p::AbstractString) = splitpath(String(p))
296 +
297 +
    function splitpath(p::String)
298 +
        drive, p = _splitdrive(p)
299 +
        out = String[]
300 +
        isempty(p) && (pushfirst!(out, p))  # "" means the current directory.
301 +
        while !isempty(p)
302 +
            dir, base = _splitdir_nodrive(p)
303 +
            dir == p && (pushfirst!(out, dir); break)  # Reached root node.
304 +
            if !isempty(base)  # Skip trailing '/' in basename
305 +
                pushfirst!(out, base)
306 +
            end
307 +
            p = dir
308 +
        end
309 +
        if !isempty(drive)  # Tack the drive back on to the first element.
310 +
            out[1] = drive * out[1]  # Note that length(out) is always >= 1.
311 +
        end
312 +
        return out
313 +
    end
314 +
    _path_separator    = "\\"
315 +
    _path_separator_re = r"[/\\]+"
316 +
    function _pathsep(paths::AbstractString...)
317 +
        for path in paths
318 +
            m = match(_path_separator_re, String(path))
319 +
            m !== nothing && return m.match[1:1]
320 +
        end
321 +
        return _path_separator
322 +
    end
323 +
    function joinpath(a::String, b::String)
324 +
        isabspath(b) && return b
325 +
        A, a = _splitdrive(a)
326 +
        B, b = _splitdrive(b)
327 +
        !isempty(B) && A != B && return string(B,b)
328 +
        C = isempty(B) ? A : B
329 +
        isempty(a)                              ? string(C,b) :
330 +
        occursin(_path_separator_re, a[end:end]) ? string(C,a,b) :
331 +
                                                  string(C,a,_pathsep(a,b),b)
332 +
    end
333 +
    joinpath(a::AbstractString, b::AbstractString) = joinpath(String(a), String(b))
334 +
    joinpath(a, b, c, paths...) = joinpath(joinpath(a, b), c, paths...)
335 +
end
336 +
286 337
@static if Sys.iswindows() && VERSION < v"1.3"
287 338
    function _splitdir_nodrive(a::String, b::String)
288 339
        m = match(r"^(.*?)([/\\]+)([^/\\]*)$", b)
@@ -292,11 +343,13 @@
Loading
292 343
    end
293 344
    function _dirname(path::String)
294 345
        m = match(r"^([^\\]+:|\\\\[^\\]+\\[^\\]+|\\\\\?\\UNC\\[^\\]+\\[^\\]+|\\\\\?\\[^\\]+:|)(.*)$"s, path)
346 +
        m === nothing && return ""
295 347
        a, b = String(m.captures[1]), String(m.captures[2])
296 348
        _splitdir_nodrive(a, b)[1]
297 349
    end
298 350
    function _splitdrive(path::String)
299 351
        m = match(r"^([^\\]+:|\\\\[^\\]+\\[^\\]+|\\\\\?\\UNC\\[^\\]+\\[^\\]+|\\\\\?\\[^\\]+:|)(.*)$"s, path)
352 +
        m === nothing && return "", path
300 353
        String(m.captures[1]), String(m.captures[2])
301 354
    end
302 355
    function _splitdir(path::String)
@@ -306,6 +359,7 @@
Loading
306 359
else
307 360
    _dirname = dirname
308 361
    _splitdir = splitdir
362 +
    _splitdrive = splitdrive
309 363
end
310 364
311 365
function valid_id(s::String)
@@ -330,7 +384,7 @@
Loading
330 384
331 385
function resolve_op_ref(x::EXPR, server)
332 386
    StaticLint.hasref(x) && return true
333 -
    typof(x) !== CSTParser.OPERATOR && return false
387 +
    !CSTParser.isoperator(x) && return false
334 388
    pf = parent_file(x)
335 389
    pf === nothing && return false
336 390
    scope = StaticLint.retrieve_scope(x)
@@ -367,36 +421,8 @@
Loading
367 421
            return true
368 422
        end
369 423
        return false
370 -
    catch
424 +
    catch err
371 425
        return false
372 426
    end
373 427
end
374 428
375 -
if VERSION < v"1.1"
376 -
    _splitdir_nodrive(path::String) = _splitdir_nodrive("", path)
377 -
    function _splitdir_nodrive(a::String, b::String)
378 -
        m = match(Base.Filesystem.path_dir_splitter, b)
379 -
        m === nothing && return (a, b)
380 -
        a = string(a, isempty(m.captures[1]) ? m.captures[2][1] : m.captures[1])
381 -
        a, String(m.captures[3])
382 -
    end
383 -
    splitpath(p::AbstractString) = splitpath(String(p))
384 -
385 -
    function splitpath(p::String)
386 -
        drive, p = splitdrive(p)
387 -
        out = String[]
388 -
        isempty(p) && (pushfirst!(out, p))  # "" means the current directory.
389 -
        while !isempty(p)
390 -
            dir, base = _splitdir_nodrive(p)
391 -
            dir == p && (pushfirst!(out, dir); break)  # Reached root node.
392 -
            if !isempty(base)  # Skip trailing '/' in basename
393 -
                pushfirst!(out, base)
394 -
            end
395 -
            p = dir
396 -
        end
397 -
        if !isempty(drive)  # Tack the drive back on to the first element.
398 -
            out[1] = drive * out[1]  # Note that length(out) is always >= 1.
399 -
        end
400 -
        return out
401 -
    end
402 -
end

@@ -21,29 +21,29 @@
Loading
21 21
    x = getcst(doc)
22 22
    loc = 0
23 23
24 -
    if typof(x) === CSTParser.FileH
25 -
        for a in x.args
24 +
    if headof(x) === :file
25 +
        for a in x
26 26
            if loc <= offset <= loc + a.span
27 27
                if CSTParser.defines_module(a) # Within module at the top-level, lets see if we can select on of the block arguments
28 -
                    if loc <= offset <= loc + a.args[1].span # Within `module` keyword, so return entire expression
28 +
                    if loc <= offset <= loc + a.trivia[1].span # Within `module` keyword, so return entire expression
29 29
                        return Position(get_position_at(doc, loc)...), Position(get_position_at(doc, loc + a.span)...), Position(get_position_at(doc, loc + a.fullspan)...)
30 30
                    end
31 -
                    if loc + a.args[1].fullspan <= offset <= loc + a.args[1].fullspan + a.args[2].span # Within name of the module, so return entire expression
31 +
                    if loc + a.trivia[1].fullspan <= offset <= loc + a.trivia[1].fullspan + a.args[2].span # Within name of the module, so return entire expression
32 32
                        return Position(get_position_at(doc, loc)...), Position(get_position_at(doc, loc + a.span)...), Position(get_position_at(doc, loc + a.fullspan)...)
33 33
                    end
34 34
35 -
                    if loc + a.args[1].fullspan + a.args[2].fullspan <= offset <= loc + a.args[1].fullspan + a.args[2].fullspan + a.args[3].span # Within the body of a module
36 -
                        loc += a.args[1].fullspan + a.args[2].fullspan
35 +
                    if loc + a.trivia[1].fullspan + a.args[2].fullspan <= offset <= loc + a.trivia[1].fullspan + a.args[2].fullspan + a.args[3].span # Within the body of a module
36 +
                        loc += a.trivia[1].fullspan + a.args[2].fullspan
37 37
                        for b in a.args[3].args
38 38
                            if loc <= offset <= loc + b.span
39 39
                                return Position(get_position_at(doc, loc)...), Position(get_position_at(doc, loc + b.span)...), Position(get_position_at(doc, loc + b.fullspan)...)
40 40
                            end
41 41
                            loc += b.fullspan
42 42
                        end
43 -
                    elseif loc + a.args[1].fullspan + a.args[2].fullspan + a.args[3].fullspan < offset < loc + a.args[1].fullspan + a.args[2].fullspan + a.args[3].fullspan + a.args[4].span # Within `end` of the module, so return entire expression
43 +
                    elseif loc + a.trivia[1].fullspan + a.args[2].fullspan + a.args[3].fullspan < offset < loc + a.trivia[1].fullspan + a.args[2].fullspan + a.args[3].fullspan + a.trivia[2].span # Within `end` of the module, so return entire expression
44 44
                        return Position(get_position_at(doc, loc)...), Position(get_position_at(doc, loc + a.span)...), Position(get_position_at(doc, loc + a.fullspan)...)
45 45
                    end
46 -
                elseif typof(a) === CSTParser.TopLevel
46 +
                elseif headof(a) === :toplevel
47 47
                    for b in a.args
48 48
                        if loc <= offset <= loc + b.span
49 49
                            return Position(get_position_at(doc, loc)...), Position(get_position_at(doc, loc + b.span)...), Position(get_position_at(doc, loc + b.fullspan)...)

@@ -1,7 +1,7 @@
Loading
1 1
function textDocument_hover_request(params::TextDocumentPositionParams, server::LanguageServerInstance, conn)
2 2
    doc = getdocument(server, URI2(params.textDocument.uri))
3 3
    x = get_expr1(getcst(doc), get_offset(doc, params.position))
4 -
    x isa EXPR && typof(x) === CSTParser.OPERATOR && resolve_op_ref(x, server)
4 +
    x isa EXPR && CSTParser.isoperator(x) && resolve_op_ref(x, server)
5 5
    documentation = get_hover(x, "", server)
6 6
    documentation = get_closer_hover(x, documentation)
7 7
    documentation = get_fcall_position(x, documentation)
@@ -33,9 +33,9 @@
Loading
33 33
        else
34 34
            try
35 35
                documentation = if binding_has_preceding_docs(b)
36 -
                    string(documentation, Expr(parentof(b.val).args[2]))
36 +
                    string(documentation, Expr(parentof(b.val).args[3]))
37 37
                elseif const_binding_has_preceding_docs(b)
38 -
                    string(documentation, Expr(parentof(parentof(b.val)).args[2]))
38 +
                    string(documentation, Expr(parentof(parentof(b.val)).args[3]))
39 39
                else
40 40
                    documentation
41 41
                end
@@ -107,16 +107,16 @@
Loading
107 107
    if b.val isa EXPR
108 108
        documentation = if binding_has_preceding_docs(b)
109 109
            # Binding has preceding docs so use them..
110 -
            string(documentation, Expr(parentof(b.val).args[2]))
110 +
            string(documentation, Expr(parentof(b.val).args[3]))
111 111
        elseif const_binding_has_preceding_docs(b)
112 -
            string(documentation, Expr(parentof(parentof(b.val)).args[2]))
112 +
            string(documentation, Expr(parentof(parentof(b.val)).args[3]))
113 113
        else
114 114
            documentation
115 115
        end
116 116
        if CSTParser.defines_function(b.val)
117 -
            documentation = string(documentation, "```julia\n", Expr(CSTParser.get_sig(b.val)), "\n```\n")
117 +
            documentation = string(ensure_ends_with(documentation), "```julia\n", Expr(CSTParser.get_sig(b.val)), "\n```\n")
118 118
        elseif CSTParser.defines_datatype(b.val)
119 -
            documentation = string(documentation, "```julia\n", Expr(b.val), "\n```\n")
119 +
            documentation = string(ensure_ends_with(documentation), "```julia\n", Expr(b.val), "\n```\n")
120 120
        end
121 121
    elseif b.val isa SymbolServer.SymStore
122 122
        return get_hover(b.val, documentation, server)
@@ -127,6 +127,8 @@
Loading
127 127
    return documentation
128 128
end
129 129
130 +
ensure_ends_with(s, c = "\n") = endswith(s, c) ? s : string(s, c)
131 +
130 132
binding_has_preceding_docs(b::StaticLint.Binding) = expr_has_preceding_docs(b.val)
131 133
132 134
function const_binding_has_preceding_docs(b::StaticLint.Binding)
@@ -138,14 +140,14 @@
Loading
138 140
expr_has_preceding_docs(x::EXPR) = is_doc_expr(parentof(x))
139 141
140 142
is_const_expr(x) = false
141 -
is_const_expr(x::EXPR) = length(x.args) == 2 && kindof(x.args[1]) === CSTParser.Tokens.CONST
143 +
is_const_expr(x::EXPR) = headof(x) === :const
142 144
143 145
is_doc_expr(x) = false
144 146
function is_doc_expr(x::EXPR)
145 -
    return typof(x) === CSTParser.MacroCall &&
146 -
        length(x.args) == 3 &&
147 -
        typof(x.args[1]) === CSTParser.GlobalRefDoc &&
148 -
        CSTParser.isstring(x.args[2])
147 +
    return CSTParser.ismacrocall(x) &&
148 +
        length(x.args) == 4 &&
149 +
        headof(x.args[1]) === :globalrefdoc &&
150 +
        CSTParser.isstring(x.args[3])
149 151
end
150 152
151 153
get_fcall_position(x, documentation, visited=nothing) = documentation
@@ -157,14 +159,14 @@
Loading
157 159
        push!(visited, x)                                # TODO: remove
158 160
    end                                                  # TODO: remove
159 161
    if parentof(x) isa EXPR
160 -
        if typof(parentof(x)) === CSTParser.Call
162 +
        if CSTParser.iscall(parentof(x))
161 163
            call_counts = StaticLint.call_nargs(parentof(x))
162 164
            call_counts[1] < 5 && return documentation
163 165
            arg_i = 0
164 -
            for i = 1:length(parentof(x).args)
165 -
                arg = parentof(x).args[i]
166 +
            for (i, arg) = enumerate(parentof(x))
166 167
                if arg == x
167 168
                    arg_i = div(i - 1, 2)
169 +
                    break
168 170
                end
169 171
            end
170 172
            arg_i == 0 && return documentation
@@ -172,7 +174,7 @@
Loading
172 174
            if StaticLint.hasref(fname) &&
173 175
                (refof(fname) isa StaticLint.Binding && refof(fname).val isa EXPR && CSTParser.defines_struct(refof(fname).val) && StaticLint.struct_nargs(refof(fname).val)[1] == call_counts[1])
174 176
                dt_ex = refof(fname).val
175 -
                args = CSTParser.defines_mutable(dt_ex) ? dt_ex.args[4] : dt_ex.args[3]
177 +
                args = dt_ex.args[3]
176 178
                args.args === nothing || arg_i > length(args.args) && return documentation
177 179
                _fieldname = CSTParser.str_value(CSTParser.get_arg_name(args.args[arg_i]))
178 180
                documentation = string("Datatype field `$_fieldname` of $(CSTParser.str_value(CSTParser.get_name(dt_ex)))", "\n", documentation)
@@ -196,27 +198,24 @@
Loading
196 198
get_closer_hover(x, documentation) = documentation
197 199
function get_closer_hover(x::EXPR, documentation)
198 200
    if parentof(x) isa EXPR
199 -
        if kindof(x) === CSTParser.Tokens.END
200 -
            if typof(parentof(x)) === CSTParser.FunctionDef
201 +
        if headof(x) === :END
202 +
            if headof(parentof(x)) === :function
201 203
                documentation = string(documentation, "Closes function definition for `", Expr(CSTParser.get_sig(parentof(x))), "`\n")
202 -
            elseif (typof(parentof(x)) === CSTParser.ModuleH || typof(parentof(x)) === CSTParser.ModuleH) && length(parentof(x).args) > 1
204 +
            elseif CSTParser.defines_module(parentof(x)) && length(parentof(x).args) > 1
203 205
                documentation = string(documentation, "Closes module definition for `", Expr(parentof(x).args[2]), "`\n")
204 -
            elseif typof(parentof(x)) === CSTParser.Struct
206 +
            elseif CSTParser.defines_struct(parentof(x))
205 207
                documentation = string(documentation, "Closes struct definition for `", Expr(CSTParser.get_sig(parentof(x))), "`\n")
206 -
            elseif typof(parentof(x)) === CSTParser.Mutable
207 -
                documentation = string(documentation, "Closes mutable struct definition for `", Expr(CSTParser.get_sig(parentof(x))), "`\n")
208 -
            elseif typof(parentof(x)) === CSTParser.For && length(parentof(x).args) > 2
208 +
            elseif headof(parentof(x)) === :for && length(parentof(x).args) > 2
209 209
                documentation = string(documentation, "Closes for-loop expression over `", Expr(parentof(x).args[2]), "`\n")
210 -
            elseif typof(parentof(x)) === CSTParser.While && length(parentof(x).args) > 2
210 +
            elseif headof(parentof(x)) === :while && length(parentof(x).args) > 2
211 211
                documentation = string(documentation, "Closes while-loop expression over `", Expr(parentof(x).args[2]), "`\n")
212 212
            else
213 -
                documentation = "Closes `$(typof(parentof(x)))` expression."
213 +
                documentation = "Closes `$(headof(parentof(x)))` expression."
214 214
            end
215 -
        elseif kindof(x) === CSTParser.Tokens.RPAREN
216 -
            if typof(parentof(x)) === CSTParser.Call && length(parentof(x).args) > 0
215 +
        elseif headof(x) === :RPAREN
216 +
            if CSTParser.iscall(parentof(x)) && length(parentof(x).args) > 0
217 217
                documentation = string(documentation, "Closes call of ", Expr(parentof(x).args[1]), "\n")
218 218
            end
219 -
        elseif kindof(x) === CSTParser.Tokens.RBRACE || kindof(x) === CSTParser.Tokens.RSQUARE
220 219
        end
221 220
    end
222 221
    return documentation

@@ -1,7 +1,7 @@
Loading
1 1
module LanguageServer
2 2
import URIParser
3 3
using JSON, REPL, CSTParser, DocumentFormat, SymbolServer, StaticLint
4 -
using CSTParser: EXPR, Tokenize.Tokens, typof, kindof, parentof, valof
4 +
using CSTParser: EXPR, Tokenize.Tokens, Tokenize.Tokens.kind, headof, parentof, valof
5 5
using StaticLint: refof, scopeof, bindingof
6 6
using UUIDs
7 7
using Base.Docs, Markdown

@@ -130,7 +130,7 @@
Loading
130 130
    for d in getdocuments_value(server)
131 131
        if d.root === doc
132 132
            d.root = d
133 -
            scopepass(getroot(d), d)
133 +
            semantic_pass(getroot(d), d)
134 134
        end
135 135
    end
136 136
end
@@ -320,7 +320,7 @@
Loading
320 320
                root = getroot(doc)
321 321
                if !(root in roots)
322 322
                    push!(roots, root)
323 -
                    scopepass(root, doc)
323 +
                    semantic_pass(root, doc)
324 324
                end
325 325
326 326
                lint!(doc, server)

@@ -1,6 +1,6 @@
Loading
1 1
const serverCapabilities = ServerCapabilities(
2 2
    TextDocumentSyncOptions(true,
3 -
    TextDocumentSyncKinds.Full,
3 +
    TextDocumentSyncKinds.Incremental,
4 4
    false,
5 5
    false,
6 6
    SaveOptions(true)),

@@ -1,5 +1,5 @@
Loading
1 1
import StaticLint: hasfile, canloadfile, loadfile, setfile, getfile, getsymbolserver, getsymbolextendeds
2 -
import StaticLint: getpath, getroot, setroot, getcst, setcst, scopepass, getserver, setserver
2 +
import StaticLint: getpath, getroot, setroot, getcst, setcst, semantic_pass, getserver, setserver
3 3
hasfile(server::LanguageServerInstance, path::String) = !isempty(path) && hasdocument(server, URI2(filepath2uri(path)))
4 4
function canloadfile(server::LanguageServerInstance, path::String)
5 5
    try

@@ -6,15 +6,14 @@
Loading
6 6
    else                                                 # TODO: remove
7 7
        push!(visited, b)                                # TODO: remove
8 8
    end                                                  # TODO: remove
9 -
10 9
    if b.type == StaticLint.CoreTypes.Function && b.val isa EXPR && CSTParser.defines_function(b.val)
11 10
        get_siginfo_from_call(b.val, sigs)
12 11
    elseif b.val isa EXPR && CSTParser.defines_struct(b.val)
13 -
        args = CSTParser.defines_mutable(b.val) ? b.val[4] : b.val[3]
12 +
        args = b.val.args[3]
14 13
        if length(args) > 0
15 14
            inner_constructor_i = findfirst(a -> CSTParser.defines_function(a), args.args)
16 15
            if inner_constructor_i !== nothing
17 -
                get_siginfo_from_call(args[inner_constructor_i], sigs)
16 +
                get_siginfo_from_call(args.args[inner_constructor_i], sigs)
18 17
            else
19 18
                params = ParameterInformation[]
20 19
                for field in args.args
@@ -64,14 +63,13 @@
Loading
64 63
    rng = Range(doc, offset:offset)
65 64
    x = get_expr(getcst(doc), offset)
66 65
    arg = 0
67 -
68 -
    if x isa EXPR && parentof(x) isa EXPR && StaticLint.is_call(parentof(x))
66 +
    if x isa EXPR && parentof(x) isa EXPR && CSTParser.iscall(parentof(x))
69 67
        if CSTParser.isidentifier(parentof(x).args[1])
70 68
            call_name = parentof(x).args[1]
71 -
        elseif StaticLint.is_curly(parentof(x).args[1]) && CSTParser.isidentifier(parentof(x).args[1].args[1])
69 +
        elseif CSTParser.iscurly(parentof(x).args[1]) && CSTParser.isidentifier(parentof(x).args[1].args[1])
72 70
            call_name = parentof(x).args[1].args[1]
73 -
        elseif StaticLint.is_getfield_w_quotenode(parentof(x).args[1])
74 -
            call_name = parentof(x).args[1].args[3].args[1]
71 +
        elseif CSTParser.is_getfield_w_quotenode(parentof(x).args[1])
72 +
            call_name = parentof(x).args[1].args[2].args[1]
75 73
        else
76 74
            call_name = nothing
77 75
        end
@@ -79,14 +77,14 @@
Loading
79 77
            get_signatures(f_binding, tls, sigs, server)
80 78
        end
81 79
    end
82 -
    if (isempty(sigs) || (typof(x) === CSTParser.PUNCTUATION  && kindof(x) === CSTParser.Tokens.RPAREN))
80 +
    if (isempty(sigs) || (headof(x) === :RPAREN))
83 81
        return SignatureHelp(SignatureInformation[], 0, 0)
84 82
    end
85 83
86 -
    if typof(x) === CSTParser.Tokens.LPAREN
84 +
    if headof(x) === :LPAREN
87 85
        arg = 0
88 86
    else
89 -
        arg = sum(CSTParser.is_comma(a) for a in parentof(x).args)
87 +
        arg = sum(headof(a) === :COMMA for a in parentof(x).trivia)
90 88
    end
91 89
    return SignatureHelp(filter(s -> length(s.parameters) > arg, sigs), 0, arg)
92 90
end
@@ -108,6 +106,12 @@
Loading
108 106
109 107
function get_definitions(x, tls, server, locations, visited=nothing) end # Fallback
110 108
109 +
function get_definitions(x::SymbolServer.ModuleStore, tls, server, locations, visited=nothing)
110 +
    if haskey(x.vals, :eval) && x[:eval] isa SymbolServer.FunctionStore
111 +
        get_definitions(x[:eval], tls, server, locations, visited)
112 +
    end
113 +
end
114 +
111 115
function get_definitions(x::T, tls, server, locations, visited=nothing) where T <: Union{SymbolServer.FunctionStore,SymbolServer.DataTypeStore}
112 116
    StaticLint.iterate_over_ss_methods(x, tls, server, function (m)
113 117
        try
@@ -152,11 +156,11 @@
Loading
152 156
        b = resolve_shadow_binding(b)
153 157
        (tls = StaticLint.retrieve_toplevel_scope(x)) === nothing && return locations
154 158
        get_definitions(b, tls, server, locations)
155 -
    elseif x isa EXPR && typof(x) === CSTParser.LITERAL && (kindof(x) === Tokens.STRING || kindof(x) === Tokens.TRIPLE_STRING)
159 +
    elseif x isa EXPR && CSTParser.isstringliteral(x)
156 160
        # TODO: move to its own function
157 161
        if sizeof(valof(x)) < 256 # AUDIT: OK
158 162
            try
159 -
                if isfile(valof(x))
163 +
                if isabspath(valof(x)) && isfile(valof(x))
160 164
                    push!(locations, Location(filepath2uri(valof(x)), Range(0, 0, 0, 0)))
161 165
                elseif !isempty(getpath(doc)) && isfile(joinpath(_dirname(getpath(doc)), valof(x)))
162 166
                    push!(locations, Location(filepath2uri(joinpath(_dirname(getpath(doc)), valof(x))), Range(0, 0, 0, 0)))
@@ -175,14 +179,14 @@
Loading
175 179
176 180
function get_file_loc(x::EXPR, offset=0, c=nothing)
177 181
    if c !== nothing
178 -
        for a in x.args
182 +
        for a in x
179 183
            a == c && break
180 184
            offset += a.fullspan
181 185
        end
182 186
    end
183 187
    if parentof(x) !== nothing
184 188
        return get_file_loc(parentof(x), offset, x)
185 -
    elseif typof(x) === CSTParser.FileH && StaticLint.hasmeta(x)
189 +
    elseif headof(x) === :file && StaticLint.hasmeta(x)
186 190
        return x.meta.error, offset
187 191
    else
188 192
        return nothing, offset
@@ -215,7 +219,6 @@
Loading
215 219
    return locations
216 220
end
217 221
218 -
# If
219 222
function find_references(b::StaticLint.Binding, refs=EXPR[], from_end=false)
220 223
    if !from_end && (b.type === StaticLint.CoreTypes.Function || b.type === StaticLint.CoreTypes.DataType)
221 224
        b = StaticLint.last_method(b)
@@ -253,17 +256,17 @@
Loading
253 256
254 257
is_valid_binding_name(name) = false
255 258
function is_valid_binding_name(name::EXPR)
256 -
    (typof(name) === CSTParser.IDENTIFIER && valof(name) isa String && !isempty(valof(name))) ||
257 -
    (typof(name) === CSTParser.OPERATOR) ||
258 -
    (typof(name) === CSTParser.NONSTDIDENTIFIER && length(name) == 2 && valof(name[2]) isa String && !isempty(valof(name[2])))
259 +
    (headof(name) === :IDENTIFIER && valof(name) isa String && !isempty(valof(name))) ||
260 +
    CSTParser.isoperator(name) ||
261 +
    (headof(name) === :NONSTDIDENTIFIER && length(name.args) == 2 && valof(name.args[2]) isa String && !isempty(valof(name.args[2])))
259 262
end
260 263
function get_name_of_binding(name::EXPR)
261 -
    if typof(name) === CSTParser.IDENTIFIER
264 +
    if headof(name) === :IDENTIFIER
262 265
        valof(name)
263 -
    elseif typof(name) === CSTParser.OPERATOR
266 +
    elseif CSTParser.isoperator(name)
264 267
        string(Expr(name))
265 -
    elseif typof(name) === CSTParser.NONSTDIDENTIFIER
266 -
        valof(name[2])
268 +
    elseif headof(name) === :NONSTDIDENTIFIER
269 +
        valof(name.args[2])
267 270
    else
268 271
        ""
269 272
    end
@@ -288,8 +291,8 @@
Loading
288 291
    if bindingof(x) !== nothing
289 292
        push!(bindings, (pos .+ (0:x.span), bindingof(x)))
290 293
    end
291 -
    if x.args !== nothing
292 -
        for a in x.args
294 +
    if length(x) > 0
295 +
        for a in x
293 296
            collect_bindings_w_loc(a, pos, bindings)
294 297
            pos += a.fullspan
295 298
        end
@@ -301,11 +304,11 @@
Loading
301 304
    if bindingof(x) isa StaticLint.Binding && valof(bindingof(x).name) isa String && bindingof(x).val isa EXPR && startswith(valof(bindingof(x).name), query)
302 305
        push!(bindings, (pos .+ (0:x.span), bindingof(x)))
303 306
    end
304 -
    if scopeof(x) !== nothing && !(typof(x) === CSTParser.FileH || typof(x) === CSTParser.ModuleH || typof(x) === CSTParser.BareModule)
307 +
    if scopeof(x) !== nothing && !(headof(x) === :file || CSTParser.defines_module(x))
305 308
        return bindings
306 309
    end
307 -
    if x.args !== nothing
308 -
        for a in x.args
310 +
    if length(x) > 0
311 +
        for a in x
309 312
            collect_toplevel_bindings_w_loc(a, pos, bindings, query=query)
310 313
            pos += a.fullspan
311 314
        end
@@ -315,7 +318,7 @@
Loading
315 318
316 319
function _binding_kind(b, server)
317 320
    if b isa StaticLint.Binding
318 -
        if b.type == nothing
321 +
        if b.type === nothing
319 322
            return 13
320 323
        elseif b.type == StaticLint.CoreTypes.Module
321 324
            return 2
@@ -367,8 +370,8 @@
Loading
367 370
end
368 371
369 372
function get_module_of(s::StaticLint.Scope, ms=[])
370 -
    if CSTParser.defines_module(s.expr) && CSTParser.isidentifier(s.expr[2])
371 -
        pushfirst!(ms, StaticLint.valofid(s.expr[2]))
373 +
    if CSTParser.defines_module(s.expr) && CSTParser.isidentifier(s.expr.args[2])
374 +
        pushfirst!(ms, StaticLint.valofid(s.expr.args[2]))
372 375
    end
373 376
    if parentof(s) isa StaticLint.Scope
374 377
        return get_module_of(parentof(s), ms)
@@ -387,7 +390,7 @@
Loading
387 390
    end
388 391
389 392
    x = get_expr1(getcst(doc), get_offset(doc, params.position))
390 -
    x isa EXPR && typof(x) === CSTParser.OPERATOR && resolve_op_ref(x, server)
393 +
    x isa EXPR && CSTParser.isoperator(x) && resolve_op_ref(x, server)
391 394
    documentation = get_hover(x, "", server)
392 395
393 396
    return documentation

@@ -34,7 +34,7 @@
Loading
34 34
35 35
function find_using_statement(x::EXPR)
36 36
    for ref in refof(x).refs
37 -
        if parentof(ref) isa EXPR && typof(parentof(ref)) === CSTParser.Using
37 +
        if StaticLint.is_in_fexpr(ref, x -> headof(x) === :using || headof(x) === :import)
38 38
            return parentof(ref)
39 39
        end
40 40
    end
@@ -50,9 +50,8 @@
Loading
50 50
    vars = Set{String}() # names that need to be imported
51 51
    # Find uses of `x` and mark edits
52 52
    for ref in refof(x).refs
53 -
        if parentof(ref) isa EXPR && typof(parentof(ref)) == CSTParser.BinaryOpCall && length(parentof(ref).args) == 3 && kindof(parentof(ref).args[2]) === CSTParser.Tokens.DOT && parentof(ref).args[1] == ref
54 -
            typof(parentof(ref).args[3]) !== CSTParser.Quotenode && continue # some malformed EXPR, skip
55 -
            childname = parentof(ref).args[3].args[1]
53 +
        if parentof(ref) isa EXPR && CSTParser.is_getfield_w_quotenode(parentof(ref)) && parentof(ref).args[1] == ref
54 +
            childname = parentof(ref).args[2].args[1]
56 55
            StaticLint.hasref(childname) && refof(childname) isa StaticLint.Binding && continue # check this isn't the name of something being explictly overwritten
57 56
            !haskey(refof(x).val.vals, Symbol(valof(childname))) && continue # skip, perhaps mark as missing ref ?
58 57
@@ -67,7 +66,7 @@
Loading
67 66
    isempty(tdes) && return
68 67
69 68
    # Add `using x: vars...` statement
70 -
    if parentof(using_stmt) isa EXPR && (typof(parentof(using_stmt)) === CSTParser.Block || typof(parentof(using_stmt)) === CSTParser.FileH)
69 +
    if parentof(using_stmt) isa EXPR && (headof(parentof(using_stmt)) === :block || headof(parentof(using_stmt)) === :file)
71 70
        # this should cover all cases
72 71
        i1 = 0
73 72
        for i = 1:length(parentof(using_stmt).args)
@@ -93,28 +92,28 @@
Loading
93 92
    JSONRPC.send(conn, workspace_applyEdit_request_type, ApplyWorkspaceEditParams(missing, WorkspaceEdit(missing, collect(values(tdes)))))
94 93
end
95 94
96 -
is_single_line_func(x) = CSTParser.defines_function(x) && typof(x) !== CSTParser.FunctionDef
95 +
is_single_line_func(x) = CSTParser.defines_function(x) && headof(x) !== :function
97 96
98 97
function expand_inline_func(x, server, conn)
99 98
    func = _get_parent_fexpr(x, is_single_line_func)
100 99
    length(func) < 3 && return
101 -
    sig = func[1]
102 -
    op = func[2]
103 -
    body = func[3]
104 -
    if typof(body) == CSTParser.Block && length(body) == 1
100 +
    sig = func.args[1]
101 +
    op = func.head
102 +
    body = func.args[2]
103 +
    if headof(body) == :block && length(body) == 1
105 104
        file, offset = get_file_loc(func)
106 105
        tde = TextDocumentEdit(VersionedTextDocumentIdentifier(file._uri, file._version), TextEdit[
107 106
            TextEdit(Range(file, offset .+ (0:func.fullspan)), string("function ", get_text(file)[offset .+ (1:sig.span)], "\n    ", get_text(file)[offset + sig.fullspan + op.fullspan .+ (1:body.span)], "\nend\n"))
108 107
        ])
109 108
        JSONRPC.send(conn, workspace_applyEdit_request_type, ApplyWorkspaceEditParams(missing, WorkspaceEdit(missing, TextDocumentEdit[tde])))
110 -
    elseif (typof(body) === CSTParser.Begin || typof(body) === CSTParser.InvisBrackets) && length(body) == 3 &&
111 -
        typof(body[2]) === CSTParser.Block && length(body[2]) > 0
109 +
    elseif (headof(body) === :begin || CSTParser.isbracketed(body)) &&
110 +
        headof(body.args[1]) === :block && length(body.args[1]) > 0
112 111
        file, offset = get_file_loc(func)
113 112
        newtext = string("function ", get_text(file)[offset .+ (1:sig.span)])
114 -
        blockoffset = offset + sig.fullspan + op.fullspan + body[1].fullspan
115 -
        for i = 1:length(body[2])
116 -
            newtext = string(newtext, "\n    ", get_text(file)[blockoffset .+ (1:body[2][i].span)])
117 -
            blockoffset += body[2][i].fullspan
113 +
        blockoffset = offset + sig.fullspan + op.fullspan + body.trivia[1].fullspan
114 +
        for i = 1:length(body.args[1].args)
115 +
            newtext = string(newtext, "\n    ", get_text(file)[blockoffset .+ (1:body.args[1].args[i].span)])
116 +
            blockoffset += body.args[1].args[i].fullspan
118 117
        end
119 118
        newtext = string(newtext, "\nend\n")
120 119
        tde = TextDocumentEdit(VersionedTextDocumentIdentifier(file._uri, file._version), TextEdit[TextEdit(Range(file, offset .+ (0:func.fullspan)), newtext)])
@@ -153,8 +152,8 @@
Loading
153 152
end
154 153
155 154
function reexport_package(x::EXPR, server, conn)
156 -
    (refof(x).type === StaticLint.CoreTypes.Module || (refof(x).val isa StaticLint.Binding && refof(x).val.type === StaticLint.CoreTypes.Module)) || (refof(x).val isa SymbolServer.ModuleStore) || return
157 -
    mod::SymbolServer.ModuleStore = refof(x).val
155 +
    (refof(x) isa SymbolServer.ModuleStore || refof(x).type === StaticLint.CoreTypes.Module || (refof(x).val isa StaticLint.Binding && refof(x).val.type === StaticLint.CoreTypes.Module)) || (refof(x).val isa SymbolServer.ModuleStore) || return
156 +
    mod::SymbolServer.ModuleStore = refof(x) isa SymbolServer.ModuleStore ? refof(x) : refof(x).val
158 157
    using_stmt = parentof(x)
159 158
    file, offset = get_file_loc(x)
160 159
    insertpos = get_next_line_offset(using_stmt)
@@ -167,13 +166,13 @@
Loading
167 166
    JSONRPC.send(conn, workspace_applyEdit_request_type, ApplyWorkspaceEditParams(missing, WorkspaceEdit(missing, TextDocumentEdit[tde])))
168 167
end
169 168
170 -
# TODO move to StaticLint
169 +
# TODO move to StaticL  int
171 170
# to be called where typof(x) === CSTParser.ModuleH/BareModule
172 171
function find_exported_names(x::EXPR)
173 172
    exported_vars = EXPR[]
174 173
    for i in 1:length(x.args[3].args)
175 174
        expr = x.args[3].args[i]
176 -
        if typof(expr) == CSTParser.Export &&
175 +
        if headof(expr) === :export
177 176
            for j = 2:length(expr)
178 177
                if CSTParser.isidentifier(expr.args[j]) && StaticLint.hasref(expr.args[j])
179 178
                    push!(exported_vars, expr.args[j])
@@ -187,7 +186,7 @@
Loading
187 186
function reexport_module(x::EXPR, server, conn)
188 187
    using_stmt = parentof(x)
189 188
    mod_expr = refof(x).val isa StaticLint.Binding ? refof(x).val.val : refof(x).val
190 -
    (mod_expr.args isa Nothing || length(mod_expr.args) < 3 || typof(mod_expr.args[3]) != CSTParser.Block || mod_expr.args[3].args isa Nothing) && return # module expr without block
189 +
    (mod_expr.args isa Nothing || length(mod_expr.args) < 3 || headof(mod_expr.args[3]) !== :block || mod_expr.args[3].args isa Nothing) && return # module expr without block
191 190
    # find export EXPR
192 191
    exported_names = find_exported_names(mod_expr)
193 192
@@ -266,6 +265,6 @@
Loading
266 265
                                    (x, params) -> is_fixable_missing_ref(x, params.context),
267 266
                                    applymissingreffix),
268 267
    "ReexportModule" => ServerAction(Command("Re-export package variables.", "ReexportModule", missing), 
269 -
                                     (x, params) -> parentof(x) isa EXPR && typof(parentof(x)) === CSTParser.Using &&  refof(x) isa StaticLint.Binding && (refof(x).type === StaticLint.CoreTypes.Module || (refof(x).val isa StaticLint.Binding && refof(x).val.type === StaticLint.CoreTypes.Module) || refof(x).val isa SymbolServer.ModuleStore),
268 +
                                     (x, params) -> StaticLint.is_in_fexpr(x, x -> headof(x) === :using || headof(x) === :import) && (refof(x) isa StaticLint.Binding && (refof(x).type === StaticLint.CoreTypes.Module || (refof(x).val isa StaticLint.Binding && refof(x).val.type === StaticLint.CoreTypes.Module) || refof(x).val isa SymbolServer.ModuleStore) || refof(x) isa SymbolServer.ModuleStore),
270 269
                                     reexport_package)
271 270
)

@@ -19,9 +19,12 @@
Loading
19 19
    elseif t isa CSTParser.Tokens.Token && t.kind == CSTParser.Tokenize.Tokens.COMMENT
20 20
        partial = is_latex_comp(t.val, offset - t.startbyte)
21 21
        !isempty(partial) && latex_completions(doc, offset, partial, CIs)
22 -
    elseif t isa CSTParser.Tokens.Token && (t.kind == CSTParser.Tokenize.Tokens.STRING || t.kind == CSTParser.Tokenize.Tokens.TRIPLE_STRING)
22 +
    elseif t isa CSTParser.Tokens.Token && (t.kind in (CSTParser.Tokenize.Tokens.STRING,
23 +
                                                       CSTParser.Tokenize.Tokens.TRIPLE_STRING,
24 +
                                                       CSTParser.Tokenize.Tokens.CMD,
25 +
                                                       CSTParser.Tokenize.Tokens.TRIPLE_CMD))
23 26
        string_completion(doc, offset, rng, t, CIs)
24 -
    elseif x isa EXPR && parentof(x) !== nothing && (typof(parentof(x)) === CSTParser.Using || typof(parentof(x)) === CSTParser.Import)
27 +
    elseif x isa EXPR && is_in_import_statement(x)
25 28
        import_completions(doc, offset, rng, ppt, pt, t, is_at_end, x, CIs, server)
26 29
    elseif t isa CSTParser.Tokens.Token && t.kind == CSTParser.Tokens.DOT && pt isa CSTParser.Tokens.Token && pt.kind == CSTParser.Tokens.IDENTIFIER
27 30
        # getfield completion, no partial
@@ -143,7 +146,7 @@
Loading
143 146
            end
144 147
        end
145 148
    end
146 -
    if parentof(x) !== nothing && typof(x) !== CSTParser.ModuleH && typof(x) !== CSTParser.BareModule
149 +
    if parentof(x) !== nothing && !CSTParser.defines_module(x)
147 150
        return collect_completions(parentof(x), spartial, rng, CIs, server, inclexported, dotcomps)
148 151
    else
149 152
        return
@@ -168,9 +171,9 @@
Loading
168 171
169 172
function is_rebinding_of_module(x)
170 173
    x isa EXPR && refof(x).type === StaticLint.CoreTypes.Module && # binding is a Module
171 -
    refof(x).val isa EXPR && typof(refof(x).val) === CSTParser.BinaryOpCall && kindof(refof(x).val.args[2]) === CSTParser.Tokens.EQ && # binding expr is an assignment
172 -
    StaticLint.hasref(refof(x).val.args[3]) && refof(refof(x).val.args[3]).type === StaticLint.CoreTypes.Module &&
173 -
    refof(refof(x).val.args[3]).val isa EXPR && typof(refof(refof(x).val.args[3]).val) === CSTParser.ModuleH# double check the rhs points to a module
174 +
    refof(x).val isa EXPR && CSTParser.isassignment(refof(x).val) && # binding expr is an assignment
175 +
    StaticLint.hasref(refof(x).val.args[2]) && refof(refof(x).val.args[2]).type === StaticLint.CoreTypes.Module &&
176 +
    refof(refof(x).val.args[2]).val isa EXPR && CSTParser.defines_module(refof(refof(x).val.args[2]).val)# double check the rhs points to a module
174 177
end
175 178
176 179
function _get_dot_completion(px, spartial, rng, CIs, server) end
@@ -179,10 +182,10 @@
Loading
179 182
        if refof(px) isa StaticLint.Binding
180 183
            if refof(px).val isa StaticLint.SymbolServer.ModuleStore
181 184
                collect_completions(refof(px).val, spartial, rng, CIs, server, true)
182 -
            elseif refof(px).val isa EXPR && typof(refof(px).val) === CSTParser.ModuleH && scopeof(refof(px).val) isa StaticLint.Scope
185 +
            elseif refof(px).val isa EXPR && CSTParser.defines_module(refof(px).val) && scopeof(refof(px).val) isa StaticLint.Scope
183 186
                collect_completions(scopeof(refof(px).val), spartial, rng, CIs, server, true)
184 187
            elseif is_rebinding_of_module(px)
185 -
                collect_completions(scopeof(refof(refof(px).val.args[3]).val), spartial, rng, CIs, server, true)
188 +
                collect_completions(scopeof(refof(refof(px).val.args[2]).val), spartial, rng, CIs, server, true)
186 189
            elseif refof(px).type isa SymbolServer.DataTypeStore
187 190
                for a in refof(px).type.fieldnames
188 191
                    a = String(a)
@@ -235,10 +238,8 @@
Loading
235 238
end
236 239
237 240
function get_import_root(x::EXPR)
238 -
    for i = 1:length(x.args)
239 -
        if typof(x.args[i]) === CSTParser.OPERATOR && kindof(x.args[i]) === CSTParser.Tokens.COLON && i > 2
240 -
            return x.args[i - 1]
241 -
        end
241 +
    if CSTParser.isoperator(headof(x.args[1])) && valof(headof(x.args[1])) == ":"
242 +
        return last(x.args[1].args[1].args)
242 243
    end
243 244
    return nothing
244 245
end
@@ -246,7 +247,7 @@
Loading
246 247
function string_completion(doc, offset, rng, t, CIs)
247 248
    path_completion(doc, offset, rng, t, CIs)
248 249
    # Need to adjust things for quotation marks
249 -
    if t.kind == CSTParser.Tokenize.Tokens.STRING
250 +
    if t.kind in (CSTParser.Tokenize.Tokens.STRING,CSTParser.Tokenize.Tokens.CMD)
250 251
        t.startbyte < offset <= t.endbyte || return
251 252
        relative_offset = offset - t.startbyte - 1
252 253
        content = t.val[2:prevind(t.val, lastindex(t.val))]
@@ -321,9 +322,13 @@
Loading
321 322
    end
322 323
end
323 324
325 +
is_in_import_statement(x::EXPR) = is_in_fexpr(x, x -> headof(x) in (:using, :import))
326 +
324 327
function import_completions(doc, offset, rng, ppt, pt, t, is_at_end, x, CIs, server)
325 -
    import_statement = parentof(x)
328 +
    import_statement = StaticLint.get_parent_fexpr(x, x -> headof(x) === :using || headof(x) === :import)
329 +
    
326 330
    import_root = get_import_root(import_statement)
331 +
    
327 332
    if (t.kind == CSTParser.Tokens.WHITESPACE && pt.kind ∈ (CSTParser.Tokens.USING, CSTParser.Tokens.IMPORT, CSTParser.Tokens.IMPORTALL, CSTParser.Tokens.COMMA, CSTParser.Tokens.COLON)) ||
328 333
        (t.kind in (CSTParser.Tokens.COMMA, CSTParser.Tokens.COLON))
329 334
        # no partial, no dot
Files Coverage
src 67.98%
Project Totals (29 files) 67.98%
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests
codecov-umbrella
Build #483043125 -
unittests

No yaml found.

Create your codecov.yml to customize your Codecov experience

Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading