Skip to content

Commit 3841c86

Browse files
committed
Merge pull request #565 from usethesource/fix/rename-refactoring/incremental-typecheck
Rename: Fix incremental type check issues (cherry picked from commit d513c3e)
1 parent 94bbf2f commit 3841c86

3 files changed

Lines changed: 67 additions & 20 deletions

File tree

rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/Rename.rsc

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import String;
4949
import lang::rascal::\syntax::Rascal;
5050

5151
import lang::rascalcore::check::Checker;
52+
import lang::rascalcore::check::BasicRascalConfig;
5253

5354
import lang::rascal::lsp::refactor::rename::Modules;
5455

@@ -486,19 +487,28 @@ private bool rascalContainsName(loc l, str name) {
486487
return false;
487488
}
488489
490+
private TModel getTModel(str modName, ModuleStatus ms) {
491+
<found, tm, ms> = getTModelForModule(modName, ms);
492+
if (!found) throw unexpectedFailure("Cannot read TModel for module \'<modName>\'\n<toString(ms.messages)>");
493+
return convertTModel2PhysicalLocs(tm);
494+
}
495+
489496
private set[TModel] rascalTModels(set[loc] fs, PathConfig pcfg) {
490497
RascalCompilerConfig ccfg = rascalCompilerConfig(pcfg)[verbose = false]
491498
[logPathConfig = false];
492499
list[str] topModuleNames = [getModuleName(mloc, pcfg) | mloc <- fs];
493500
ms = rascalTModelForNames(topModuleNames, ccfg, dummy_compile1);
494501
495-
set[TModel] tmodels = {};
496-
for (str modName <- ms.moduleLocs) {
497-
<found, tm, ms> = getTModelForModule(modName, ms);
498-
if (!found) throw unexpectedFailure("Cannot read TModel for module \'<modName>\'\n<toString(ms.messages)>");
499-
tmodels += convertTModel2PhysicalLocs(tm);
502+
map[str, TModel] tmodels = ();
503+
modsToDo = toSet(topModuleNames);
504+
while ({str modName, *rest} := modsToDo) {
505+
modsToDo = rest;
506+
tm = getTModel(modName, ms);
507+
tmodels[modName] = tm;
508+
depNames = domain(tm.store[key_bom]);
509+
modsToDo += depNames - domain(tmodels);
500510
}
501-
return tmodels;
511+
return range(tmodels);
502512
}
503513
504514
ProjectFiles preloadFiles(set[loc] workspaceFolders, loc cursorLoc) {

rascal-lsp/src/main/rascal/lang/rascal/tests/rename/Performance.rsc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ module lang::rascal::tests::rename::Performance
2929
import lang::rascal::tests::rename::TestUtils;
3030
import lang::rascal::lsp::refactor::Exception;
3131

32+
import lang::rascalcore::check::Checker;
33+
import lang::rascalcore::check::RascalConfig;
34+
35+
import IO;
3236
import List;
37+
import util::Reflective;
3338

3439
int LARGE_TEST_SIZE = 200;
3540
test bool largeTest() = testRenameOccurrences(({0} | it + {foos + 3, foos + 4, foos + 5} | i <- [0..LARGE_TEST_SIZE], foos := 5 * i), (
@@ -42,3 +47,21 @@ test bool largeTest() = testRenameOccurrences(({0} | it + {foos + 3, foos + 4, f
4247

4348
@expected{unsupportedRename}
4449
test bool failOnError() = testRename("int foo = x + y;");
50+
51+
test bool incrementalTypeCheck() {
52+
procLoc = |memory://tests/incremental|;
53+
pcfg = getTestPathConfig(procLoc);
54+
procSrc = pcfg.srcs[0];
55+
56+
modName = "A";
57+
moduleLoc = procSrc + "<modName>.rsc";
58+
writeFile(moduleLoc, "module <modName>
59+
'int foo() = 1;
60+
'void main() { x = foo(); }
61+
");
62+
63+
ms = rascalTModelForNames([modName], rascalCompilerConfig(pcfg), dummy_compile1);
64+
res = testRenameOccurrences({byLoc(modName, moduleLoc, {0, 1})});
65+
remove(procLoc);
66+
return res;
67+
}

rascal-lsp/src/main/rascal/lang/rascal/tests/rename/TestUtils.rsc

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ import util::Reflective;
5656

5757
//// Fixtures and utility functions
5858
data TestModule = byText(str name, str body, set[int] nameOccs, str newName = name, set[int] skipCursors = {})
59-
| byLoc(loc file, set[int] nameOccs, str newName = name, set[int] skipCursors = {});
59+
| byLoc(str name, loc file, set[int] nameOccs, str newName = name, set[int] skipCursors = {});
6060

6161
private list[DocumentEdit] sortEdits(list[DocumentEdit] edits) = [sortChanges(e) | e <- edits];
6262

@@ -68,10 +68,20 @@ private default DocumentEdit sortChanges(DocumentEdit e) = e;
6868
private void verifyTypeCorrectRenaming(loc root, Edits edits, PathConfig pcfg) {
6969
list[loc] editLocs = [l | /replace(l, _) := edits<0>];
7070
assert size(editLocs) == size(toSet(editLocs)) : "Duplicate locations in suggested edits - VS Code cannot handle this";
71+
72+
// Back-up sources
73+
loc backupLoc = |memory://tests/backup|;
74+
remove(backupLoc, recursive = true);
75+
copy(root, backupLoc, recursive = true);
76+
7177
executeDocumentEdits(sortEdits(edits<0>));
7278
remove(pcfg.resources);
7379
RascalCompilerConfig ccfg = rascalCompilerConfig(pcfg)[verbose = false][logPathConfig = false];
7480
throwAnyErrors(checkAll(root, ccfg));
81+
82+
// Restore back-up
83+
remove(root, recursive = true);
84+
move(backupLoc, root, overwrite = true);
7585
}
7686

7787
bool expectEq(&T expected, &T actual, str epilogue = "") {
@@ -92,29 +102,31 @@ bool expectEq(&T expected, &T actual, str epilogue = "") {
92102

93103
bool testRenameOccurrences(set[TestModule] modules, str oldName = "foo", str newName = "bar") {
94104
bool success = true;
95-
for (mm <- modules, cursorOcc <- (mm.nameOccs - mm.skipCursors)) {
96-
str testName = "Test_<mm.name>_<cursorOcc>";
97-
loc testDir = |memory://tests/rename/<testName>|;
98105

99-
if(any(m <- modules, m is byLoc)) {
100-
testDir = cover([m.file | m <- modules, m is byLoc]);
106+
bool moduleExistsOnDisk = any(mmm <- modules, mmm is byLoc);
107+
for (mm <- modules, cursorOcc <- (mm.nameOccs - mm.skipCursors)) {
108+
loc testDir = |unknown:///|;
109+
if (moduleExistsOnDisk){
110+
testDir = cover([m.file.parent | m <- modules, m is byLoc]).parent;
101111
} else {
102112
// If none of the modules refers to an existing file, clear the test directory before writing files.
113+
str testName = "Test_<mm.name>_<cursorOcc>";
114+
testDir = |memory://tests/rename/<testName>|;
103115
remove(testDir);
104116
}
105117

106118
pcfg = getTestPathConfig(testDir);
107-
modulesByLocation = {mByLoc | m <- modules, mByLoc := (m is byLoc ? m : byLoc(storeTestModule(testDir, m.name, m.body), m.nameOccs, newName = m.newName, skipCursors = m.skipCursors))};
119+
modulesByLocation = {mByLoc | m <- modules, mByLoc := (m is byLoc ? m : byLoc(m.name, storeTestModule(testDir, m.name, m.body), m.nameOccs, newName = m.newName, skipCursors = m.skipCursors))};
108120

109-
for (byLoc(loc ml, _) <- modulesByLocation) {
121+
for (m <- modulesByLocation) {
110122
try {
111-
parseModuleWithSpaces(ml);
123+
parseModuleWithSpaces(m.file);
112124
} catch _: {
113125
throw "Parse error in test module <ml>";
114126
}
115127
}
116128

117-
cursorT = findCursor([m.file | m <- modulesByLocation, getModuleName(m.file, pcfg) == mm.name][0], oldName, cursorOcc);
129+
cursorT = findCursor([m.file | m <- modulesByLocation, m.name == mm.name][0], oldName, cursorOcc);
118130

119131
println("Renaming \'<oldName>\' from <cursorT.src>");
120132
edits = rascalRenameSymbol(cursorT, toSet(pcfg.srcs), newName, PathConfig(loc _) { return pcfg; });
@@ -149,11 +161,13 @@ bool testRenameOccurrences(set[TestModule] modules, str oldName = "foo", str new
149161
success = false;
150162
}
151163

152-
for (success, src <- pcfg.srcs) {
153-
verifyTypeCorrectRenaming(src, edits, pcfg);
164+
if (success) {
165+
verifyTypeCorrectRenaming(testDir, edits, pcfg);
154166
}
155167

156-
remove(testDir);
168+
if (!moduleExistsOnDisk) {
169+
remove(testDir);
170+
}
157171
}
158172

159173
return success;
@@ -186,7 +200,7 @@ bool testRename(str stmtsStr, int cursorAtOldNameOccurrence = 0, str oldName = "
186200
return false;
187201
}
188202

189-
private PathConfig getTestPathConfig(loc testDir) {
203+
public PathConfig getTestPathConfig(loc testDir) {
190204
return pathConfig(
191205
bin=testDir + "bin",
192206
libs=[|lib://rascal|],

0 commit comments

Comments
 (0)