diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/compiler/analyzer.zc | 3 | ||||
| -rw-r--r-- | src/compiler/base.zc | 25 | ||||
| -rw-r--r-- | src/lsp/server.zc | 30 |
3 files changed, 54 insertions, 4 deletions
diff --git a/src/compiler/analyzer.zc b/src/compiler/analyzer.zc index 103f732..ff6a6c1 100644 --- a/src/compiler/analyzer.zc +++ b/src/compiler/analyzer.zc @@ -1002,9 +1002,10 @@ int lend_drop(int dep, int from) { // or untracked memory, 7 freed by reassigning it, 8 pushed into end_whom. int end_why; char* end_whom; int end_owner(int i) { - int j = lbase; word info = talloc(5); + int j = lbase; word info = talloc(6); lend_check(i); info[0] = lname[i]; info[1] = lpos[i]; info[2] = tpack(); info[3] = end_why; info[4] = end_whom; + info[5] = lreadpos[i]; if (!info[5]) info[5] = info[2]; // the owner's own token where it ended, for the editor end_why = 0; end_whom = 0; local_ended[i] = info[2]; local_end_info[i] = info; lstate[i] = S_DEAD; while (j < nloc) { diff --git a/src/compiler/base.zc b/src/compiler/base.zc index bfed062..7e4b5bc 100644 --- a/src/compiler/base.zc +++ b/src/compiler/base.zc @@ -415,6 +415,11 @@ int s_new_k, s_recycle_leaf; // server streams diagnostics and drops a check whose source has been replaced word chk_hook; int cmode, chkabort, chkfuel; word dgbuf, dggrow; int dgcap, dgpos, dgn, dgopen, dgprev, dgmode; +// related places of check-mode records, for the editor: DGREL_W words each, [the record's +// offset in dgbuf, the packed place where the owner ended, the packed place of the owner's +// declaration, how it ended (end_why), the owner's name]. reset by chk_begin. +const int DGREL_W = 5; +word dgrel; int dgreln, dgrelcap; // expand a diagnostic in progress, keeping its output offset within the buffer. int dg_expand() { dgbuf = chk_resize(dgbuf, dgpos + 5 + rt.outn, dgcap * 2); @@ -433,8 +438,22 @@ int dg_expand() { int probe_off = -1, probe_has, probe_n, probe_cap, probe_static; char** probe_name; word probe_kind, probe_state, probe_type, probe_decl, probe_mem; char* curinc; int incdepth, dgdrop; int incplace; // how many includes deep the compile is; a record to throw away; the place of the outermost include +// an open record's range becomes the packed place p (the use itself, not the token after it). +int dg_place(int p) { + if (!cmode || !dgopen || incdepth > 0 || !p || (p & 0xFFFFFF) != tline) return 0; + dgbuf[dgpos + 1] = p & 0xFFFFFF; dgbuf[dgpos + 2] = ((p >> 40) & 0x1FFFFF) - 1; dgbuf[dgpos + 3] = (p >> 24) & 0xFFFF; + return 0; +} +int dg_related(int end_place, int decl_place, int why, char* owner) { + if (!cmode || !dgopen || dgdrop || incdepth > 0) return 0; + if (dgreln == dgrelcap) { int cap = dgrelcap * 2; if (!cap) cap = 16; dgrel = chk_resize(dgrel, dgreln * DGREL_W, cap * DGREL_W); dgrelcap = cap; } + word e = dgrel + dgreln * DGREL_W; + e[0] = dgpos; e[1] = end_place; e[2] = decl_place; e[3] = why; e[4] = owner; dgreln++; + return 0; +} int dg_close() { if (!dgopen) return 0; + if (dgdrop && dgreln && dgrel[(dgreln - 1) * DGREL_W] == dgpos) dgreln--; // its record is thrown away if (!dgdrop) { dgbuf[dgpos + 4] = rt.outn; dgpos = dgpos + 5 + rt.outn; dgn++; } dgdrop = 0; dgopen = 0; rt.outmode = dgmode; rt.outgrow = dggrow; @@ -470,7 +489,7 @@ word[256] dgseen_initial; word dgseen = dgseen_initial; int dgseen_cap = 256, dg // start and stop a check run. chk_begin points the diagnostics at a buffer // the caller owns; chk_end flushes any open record and restores output. int chk_begin(int buf, int cap) { - cmode = 1; chkabort = 0; chkfuel = 0; dgbuf = buf; dgcap = cap; dgpos = 0; dgn = 0; dgopen = 0; + cmode = 1; chkabort = 0; chkfuel = 0; dgbuf = buf; dgcap = cap; dgpos = 0; dgn = 0; dgopen = 0; dgreln = 0; nerr = 0; panic = 0; dgmode = rt.outmode; rt.fill_w(dgseen, 0, dgseen_cap); dgseen_n = 0; return 0; } @@ -963,7 +982,7 @@ int cerr(char* msg) { // "r: used after it was given away; r borrows t, and t was freed on line 5 (t declared on line 4)" int ended_message(char* use, word info, char* root, int cause) { char* owner = root; int why = 0; char* whom = 0; - if (info) { owner = info[0]; why = info[3]; whom = info[4]; } + if (info) { owner = info[0]; why = info[3]; whom = info[4]; dg_related(info[5], info[1], why, owner); } rt.put_s(use); rt.put_s(": used after it was given away; "); if (!rt.eq_w(use, owner)) { rt.put_s(use); rt.put_s(" borrows "); rt.put_s(owner); rt.put_s(", and "); } rt.put_s(owner); @@ -989,7 +1008,7 @@ int cerrn(int i, char* msg) { if (!info && local_end_info) info = local_end_info[root]; if (info) cause = info[2]; else if (local_ended) cause = local_ended[root]; } - if (cause && !panic && !dry) { errat(); ended_message(lname[i], info, lname[root], cause); errend(); } + if (cause && !panic && !dry) { errat(); dg_place(lreadpos[i]); ended_message(lname[i], info, lname[root], cause); errend(); } else serrn(lname[i], msg); } return 0; diff --git a/src/lsp/server.zc b/src/lsp/server.zc index 6f4ce67..65881a9 100644 --- a/src/lsp/server.zc +++ b/src/lsp/server.zc @@ -258,6 +258,35 @@ int wpos(int off) { wc('}'); return 0; } +// a packed compiler place (tpack) as an lsp location in document gd. +int wplace(int p) { + int o = ((p >> 40) & 0x1FFFFF) - 1, n = (p >> 24) & 0xFFFF; + if (o < 0) o = 0; if (o > plen) o = plen; + if (n < 1) n = 1; if (o + n > plen) n = plen - o; + ws("{\"uri\":"); wjs(duri[gd], dulen[gd]); ws(",\"range\":{\"start\":"); wpos(o); ws(",\"end\":"); wpos(o + n); ws("}}"); + return 0; +} +// the related places the compiler recorded for the record at offset at (run.dg_related): +// where the owner ended and where it was declared, as relatedInformation. +int diag_related(int at) { + int k = 0, why; word e; char* what; + while (k < run.dgreln) { + e = run.dgrel + k * run.DGREL_W; + if (e[0] == at) { + why = e[3]; what = " ended here"; + if (why == 1) what = " was freed here"; else if (why == 2) what = " was given to a .d parameter here"; + else if (why == 3) what = " was moved here"; else if (why == 4) what = " was stored into a container here"; + else if (why == 5) what = " was returned here"; else if (why == 6) what = " was stored in a global here"; + else if (why == 7) what = " was freed by this reassignment"; else if (why == 8) what = " was pushed into an array here"; + ws(",\"relatedInformation\":[{\"location\":"); wplace(e[1]); ws(",\"message\":\"owner "); ws(e[4]); ws(what); ws("\"}"); + if (e[2]) { ws(",{\"location\":"); wplace(e[2]); ws(",\"message\":\"owner "); ws(e[4]); ws(" is declared here\"}"); } + wc(']'); + return 0; + } + k++; + } + return 0; +} // writes the publishDiagnostics message for document gd from dgb. each record // becomes a range (the whole line when the compiler only knew the line), a // severity and its message. @@ -295,6 +324,7 @@ int gen_diag() { ws("{\"range\":{\"start\":"); wpos(o); ws(",\"end\":"); wpos(e); ws("},\"severity\":"); wn(sev); ws(",\"source\":\"zc\",\"message\":"); wjs(dgb + at + 5, n); + diag_related(at); wc('}'); at = at + 5 + n; } |
