Skip to content

Commit 7374771

Browse files
authored
Merge pull request #428 from codefori/worksofliam/issue427
Fix collection of prototypes
2 parents 0101f28 + 507a3de commit 7374771

File tree

7 files changed

+203
-26
lines changed

7 files changed

+203
-26
lines changed

extension/server/src/providers/documentSymbols.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export default async function documentSymbolProvider(handler: DocumentSymbolPara
5252
prettyKeywords(proc.keyword),
5353
proc.prototype ? SymbolKind.Interface : SymbolKind.Function,
5454
Range.create(proc.range.start!, 0, proc.range.end!, 0),
55-
Range.create(proc.range.start!, 0, proc.range.start!, 0),
55+
Range.create(proc.range.start!, 0, proc.range.end!, 0),
5656
);
5757

5858
if (proc.scope) {
@@ -62,8 +62,8 @@ export default async function documentSymbolProvider(handler: DocumentSymbolPara
6262
subitem.name,
6363
prettyKeywords(subitem.keyword),
6464
SymbolKind.Property,
65-
Range.create(subitem.position.range.line, 0, subitem.position.range.line, 0),
66-
Range.create(subitem.position.range.line, 0, subitem.position.range.line, 0)
65+
Range.create(subitem.range.start!, 0, subitem.range.end!, 0),
66+
Range.create(subitem.range.start!, 0, subitem.range.end!, 0)
6767
));
6868

6969
procDef.children.push(...getScopeVars(proc.scope));
@@ -80,7 +80,7 @@ export default async function documentSymbolProvider(handler: DocumentSymbolPara
8080
prettyKeywords(def.keyword),
8181
SymbolKind.Function,
8282
Range.create(def.range.start!, 0, def.range.end!, 0),
83-
Range.create(def.range.start!, 0, def.range.start!, 0),
83+
Range.create(def.range.start!, 0, def.range.end!, 0),
8484
)),
8585

8686
...scope.variables
@@ -89,8 +89,8 @@ export default async function documentSymbolProvider(handler: DocumentSymbolPara
8989
def.name,
9090
prettyKeywords(def.keyword),
9191
SymbolKind.Variable,
92-
Range.create(def.position.range.line, 0, def.position.range.line, 0),
93-
Range.create(def.position.range.line, 0, def.position.range.line, 0)
92+
Range.create(def.range.start!, 0, def.range.end!, 0),
93+
Range.create(def.range.start!, 0, def.range.end!, 0)
9494
))
9595
);
9696

@@ -102,7 +102,7 @@ export default async function documentSymbolProvider(handler: DocumentSymbolPara
102102
prettyKeywords(def.keyword),
103103
SymbolKind.Constant,
104104
Range.create(def.range.start!, 0, def.range.end!, 0),
105-
Range.create(def.range.start!, 0, def.range.start!, 0)
105+
Range.create(def.range.start!, 0, def.range.end!, 0)
106106
);
107107

108108
if (def.subItems.length > 0) {
@@ -112,8 +112,8 @@ export default async function documentSymbolProvider(handler: DocumentSymbolPara
112112
subitem.name,
113113
prettyKeywords(subitem.keyword),
114114
SymbolKind.Property,
115-
Range.create(subitem.position.range.line, 0, subitem.position.range.line, 0),
116-
Range.create(subitem.position.range.line, 0, subitem.position.range.line, 0)
115+
Range.create(subitem.range.start!, 0, subitem.range.start!, 0),
116+
Range.create(subitem.range.end!, 0, subitem.range.end!, 0)
117117
));
118118
}
119119

language/models/cache.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,17 @@ export default class Cache {
6262
get symbols() {
6363
if (this.symbolCache) return this.symbolCache;
6464

65-
this.symbolCache = Array.from(this.symbolRegister.values()).flat(1);
65+
this.symbolCache = Array.from(this.symbolRegister.values()).flat(1).sort((a, b) => {
66+
if (a.position && b.position) {
67+
return a.position.range.line - b.position.range.line
68+
} else if (a.range.start && b.range.start) {
69+
return a.range.start - b.range.start;
70+
} else if (a.position) {
71+
return -1;
72+
} else if (b.position) {
73+
return 1;
74+
}
75+
});
6676

6777
return this.symbolCache;
6878
}

language/parser.ts

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ export default class Parser {
233233
}
234234
}
235235

236-
let currentGroup: "structs"|"procedures"|"constants";
236+
let currentGroup: "structs"|"procedures"|"constants"|"parameters";
237237

238238
let definedMacros: string[] = [];
239239

@@ -878,6 +878,11 @@ export default class Parser {
878878
range: tokens[1].range
879879
};
880880

881+
currentItem.range = {
882+
start: currentStmtStart.line,
883+
end: lineNumber
884+
};
885+
881886
scope.addSymbol(currentItem);
882887
resetDefinition = true;
883888
}
@@ -897,6 +902,11 @@ export default class Parser {
897902
range: tokens[1].range
898903
};
899904

905+
currentItem.range = {
906+
start: currentStmtStart.line,
907+
end: lineNumber
908+
};
909+
900910
scope.addSymbol(currentItem);
901911
resetDefinition = true;
902912
}
@@ -1346,6 +1356,11 @@ export default class Parser {
13461356
range: tokens[0].range
13471357
};
13481358

1359+
currentSub.range = {
1360+
start: currentStmtStart.line,
1361+
end: lineNumber
1362+
};
1363+
13491364
// Add comments from the tags
13501365
if (currentItem.type === `procedure`) {
13511366
const paramTags = currentItem.tags.filter(tag => tag.tag === `param`);
@@ -1628,6 +1643,11 @@ export default class Parser {
16281643
path: fileUri,
16291644
range: dSpec.field.range
16301645
};
1646+
1647+
currentItem.range = {
1648+
start: currentNameToken.range.line,
1649+
end: currentItem.position.range.line
1650+
};
16311651

16321652
scope.addSymbol(currentItem);
16331653
resetDefinition = true;
@@ -1646,6 +1666,11 @@ export default class Parser {
16461666
range: currentNameToken.range
16471667
};
16481668

1669+
currentItem.range = {
1670+
start: currentNameToken.range.line,
1671+
end: currentItem.position.range.line
1672+
};
1673+
16491674
scope.addSymbol(currentItem);
16501675
resetDefinition = true;
16511676
break;
@@ -1708,6 +1733,8 @@ export default class Parser {
17081733
...dSpec.keywords
17091734
}
17101735
}
1736+
} else {
1737+
currentGroup = `parameters`;
17111738
}
17121739
break;
17131740

@@ -1717,7 +1744,6 @@ export default class Parser {
17171744
switch (currentGroup) {
17181745
case `structs`:
17191746
case `procedures`:
1720-
17211747
// We have to do this backwards lookup to find the definition
17221748
// because in fixed format, currentItem is not defined. So
17231749
// we go find the latest procedure/structure defined
@@ -1729,13 +1755,19 @@ export default class Parser {
17291755

17301756
currentItem = validScope[currentGroup][validScope[currentGroup].length - 1];
17311757
break;
1758+
1759+
case `parameters`:
1760+
currentItem = new Declaration(`struct`);
1761+
currentItem.name = PROGRAMPARMS_NAME;
1762+
break;
17321763
}
17331764
}
17341765

17351766
if (currentItem) {
1767+
const isProgramParameter = currentItem.name === PROGRAMPARMS_NAME;
17361768

17371769
// This happens when it's a blank parm.
1738-
const baseToken = dSpec.type || dSpec.len;
1770+
const baseToken = dSpec.type || dSpec.len;
17391771
if (!potentialName && baseToken) {
17401772
pushPotentialNameToken({
17411773
...baseToken,
@@ -1746,7 +1778,7 @@ export default class Parser {
17461778
const currentNameToken = getPotentialNameToken();
17471779

17481780
if (potentialName) {
1749-
currentSub = new Declaration(`subitem`);
1781+
currentSub = new Declaration(isProgramParameter ? `parameter` : `subitem`);
17501782
currentSub.name = currentNameToken?.value || NO_NAME;
17511783
currentSub.keyword = {
17521784
...prettyTypeFromToken(dSpec),
@@ -1758,10 +1790,19 @@ export default class Parser {
17581790
range: currentNameToken?.range
17591791
};
17601792

1793+
currentSub.range = {
1794+
start: lineNumber,
1795+
end: lineNumber
1796+
}
1797+
17611798
// If the parameter has likeds, add the subitems to make it a struct.
17621799
await expandDs(fileUri, currentNameToken, currentSub);
17631800

1764-
currentItem.subItems.push(currentSub);
1801+
if (isProgramParameter) {
1802+
scope.addSymbol(currentSub);
1803+
} else {
1804+
currentItem.subItems.push(currentSub);
1805+
}
17651806
currentSub = undefined;
17661807

17671808
resetDefinition = true;
@@ -1772,12 +1813,15 @@ export default class Parser {
17721813
...currentItem.subItems[currentItem.subItems.length - 1].keyword,
17731814
...prettyTypeFromToken(dSpec),
17741815
...dSpec.keywords
1775-
}
1816+
};
1817+
1818+
currentItem.subItems[currentItem.subItems.length - 1].range.end = lineNumber;
17761819
} else {
17771820
currentItem.keyword = {
17781821
...currentItem.keyword,
17791822
...dSpec.keywords
17801823
}
1824+
17811825
}
17821826
}
17831827
}

tests/suite/basics.test.ts

Lines changed: 125 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
import path from "path";
3-
import setupParser from "../parserSetup";
3+
import setupParser, { getFileContent } from "../parserSetup";
44
import Linter from "../../language/linter";
55
import { test, expect } from "vitest";
66

@@ -125,6 +125,12 @@ test('vitestTest5', async () => {
125125
expect(cache.procedures[0].subItems.length).toBe(0);
126126
expect(cache.procedures[1].subItems.length).toBe(1);
127127

128+
const setValue = cache.procedures[1];
129+
expect(setValue.name).toBe(`setValue`);
130+
expect(setValue.subItems[0].name).toBe(`newValue`);
131+
expect(setValue.subItems[0].range.start).toBe(10);
132+
expect(setValue.subItems[0].range.end).toBe(10);
133+
128134
let typeData;
129135
for (const proc of cache.procedures) {
130136
typeData = cache.resolveType(cache.procedures[0]);
@@ -1746,6 +1752,7 @@ test('const value #400', async () => {
17461752
const pi = cache.find(`PI`);
17471753
expect(pi.name).toBe(`PI`);
17481754
expect(pi.keyword[`CONST`]).toBe(`3.14159`);
1755+
expect(pi.range).toMatchObject({ start: 1, end: 1 });
17491756
});
17501757

17511758
test('dcl-enum range (#425)', async () => {
@@ -1772,4 +1779,120 @@ test('dcl-enum range (#425)', async () => {
17721779
expect(constants[0].range).toMatchObject({ start: 5, end: 8 });
17731780
expect(lines[constants[0].range.start]).toBe(`dcl-enum myenum qualified;`);
17741781
expect(lines[constants[0].range.end]).toBe(`end-enum;`);
1775-
});
1782+
});
1783+
1784+
test('correct ranges (#427)', async () => {
1785+
const lines = [
1786+
` d extproc('main')`,
1787+
` d io_test 12345a options(*varsize)`,
1788+
` d testing...`,
1789+
` d pr`,
1790+
` d extproc('testing')`,
1791+
` d msgInfo 787a const varying options(*varsize)`,
1792+
` d tester s like(ai_tester)`,
1793+
` d system s like(ai_system)`,
1794+
` d fmtType s like(ai_fmtType)`,
1795+
` d TYPE_VAR_CHAR...`,
1796+
` d c x'8004'`,
1797+
` /free`,
1798+
``,
1799+
` *inlr = *on;`,
1800+
``,
1801+
` if (%parms() >= p_tester and %addr(ai_tester) <> *null);`,
1802+
` tester = ai_tester;`,
1803+
` endif;`,
1804+
``,
1805+
``,
1806+
` //*==========================================================================================*`,
1807+
` //* Program entry point *`,
1808+
` //*==========================================================================================*`,
1809+
``,
1810+
` d TESTING...`,
1811+
` d pi`,
1812+
` d aio_test 12345a options(*varsize)`,
1813+
` d ai_lenFldInf 10i 0 const`,
1814+
` d ai_format 8a const`,
1815+
` d ai_qFile const likeds(qObj_t)`,
1816+
` d ai_rcdFmt 10a const`,
1817+
` d ai_tester 1a const options(*nopass)`,
1818+
` d ai_system 10a const options(*nopass)`,
1819+
` d ai_fmtType 10a const options(*nopass)`,
1820+
``,
1821+
` d p_tester c 7`,
1822+
` d p_system c 8`,
1823+
` d p_fmtType c 9`,
1824+
``,
1825+
` d tester s like(ai_tester)`,
1826+
` d system s like(ai_system)`,
1827+
` d fmtType s like(ai_fmtType)`,
1828+
``,
1829+
``,
1830+
` //*==========================================================================================*`,
1831+
` //* Main procedure *`,
1832+
` //*==========================================================================================*`,
1833+
` p main...`,
1834+
` p b`,
1835+
` d pi`,
1836+
` d io_test 12345a options(*varsize)`,
1837+
` p e`,
1838+
];
1839+
1840+
const cache = await parser.getDocs(uri, lines.join(`\n`), { ignoreCache: true, withIncludes: false });
1841+
1842+
const testingPr = cache.find(`testing`);
1843+
expect(testingPr.range.start).toBe(2);
1844+
expect(testingPr.range.end).toBe(5);
1845+
1846+
expect(cache.parameters.length).toBe(8);
1847+
expect(cache.parameters[0].name).toBe(`aio_test`);
1848+
expect(cache.parameters[0].range.start).toBe(26)
1849+
expect(cache.parameters[7].name).toBe(`ai_fmtType`);
1850+
expect(cache.parameters[7].range.start).toBe(33)
1851+
1852+
const mainProcedure = cache.find(`main`);
1853+
const procStart = mainProcedure.range.start;
1854+
const procEnd = mainProcedure.range.end;
1855+
expect(procEnd-procStart).toBe(4);
1856+
1857+
const constants = cache.constants;
1858+
expect(constants.length).toBe(4);
1859+
1860+
expect(constants[0].name).toBe(`TYPE_VAR_CHAR`);
1861+
expect(constants[0].range.start).toBe(9);
1862+
expect(constants[0].range.end).toBe(10);
1863+
expect(constants[0].keyword[`CONST`]).toBe(`x'8004'`);
1864+
1865+
expect(constants[1].name).toBe(`p_tester`);
1866+
expect(constants[1].range.start).toBe(35);
1867+
expect(constants[1].range.end).toBe(35);
1868+
expect(constants[1].keyword[`CONST`]).toBe(`7`);
1869+
1870+
expect(constants[2].name).toBe(`p_system`);
1871+
expect(constants[2].range.start).toBe(36);
1872+
expect(constants[2].range.end).toBe(36);
1873+
1874+
expect(constants[3].name).toBe(`p_fmtType`);
1875+
expect(constants[3].range.start).toBe(37);
1876+
expect(constants[3].range.end).toBe(37);
1877+
expect(constants[3].keyword[`CONST`]).toBe(`9`);
1878+
});
1879+
1880+
// test('scoobydo', async () => {
1881+
// const content = await getFileContent(path.join(__dirname, `..`, `rpgle`, `testing.rpgle`));
1882+
// const lines = content.split(/\r?\n/);
1883+
// const cache = await parser.getDocs(uri, content, { ignoreCache: true, withIncludes: false });
1884+
1885+
// const kill = cache.findAll(`kill`);
1886+
1887+
// const killPrototype = kill[0];
1888+
// expect(killPrototype.name).toBe(`kill`);
1889+
// expect(killPrototype.prototype).toBeTruthy();
1890+
// expect(killPrototype.range.start).toBe(71);
1891+
// expect(killPrototype.range.end).toBe(74);
1892+
1893+
// const killProc = kill[1];
1894+
// expect(killProc.name).toBe(`kill`);
1895+
// expect(killProc.prototype).toBeFalsy();
1896+
// expect(killProc.range.start).toBe(741);
1897+
// expect(killProc.range.end).toBe(761);
1898+
// });

0 commit comments

Comments
 (0)