Skip to content

Commit

Permalink
Merge pull request #565 from usethesource/fix/rename-refactoring/incr…
Browse files Browse the repository at this point in the history
…emental-typecheck

Rename: Fix incremental type check issues
(cherry picked from commit d513c3e)
  • Loading branch information
toinehartman committed Jan 29, 2025
1 parent 94bbf2f commit 3841c86
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 20 deletions.
22 changes: 16 additions & 6 deletions rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/Rename.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import String;
import lang::rascal::\syntax::Rascal;

import lang::rascalcore::check::Checker;
import lang::rascalcore::check::BasicRascalConfig;

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

Expand Down Expand Up @@ -486,19 +487,28 @@ private bool rascalContainsName(loc l, str name) {
return false;
}
private TModel getTModel(str modName, ModuleStatus ms) {
<found, tm, ms> = getTModelForModule(modName, ms);
if (!found) throw unexpectedFailure("Cannot read TModel for module \'<modName>\'\n<toString(ms.messages)>");
return convertTModel2PhysicalLocs(tm);
}
private set[TModel] rascalTModels(set[loc] fs, PathConfig pcfg) {
RascalCompilerConfig ccfg = rascalCompilerConfig(pcfg)[verbose = false]
[logPathConfig = false];
list[str] topModuleNames = [getModuleName(mloc, pcfg) | mloc <- fs];
ms = rascalTModelForNames(topModuleNames, ccfg, dummy_compile1);
set[TModel] tmodels = {};
for (str modName <- ms.moduleLocs) {
<found, tm, ms> = getTModelForModule(modName, ms);
if (!found) throw unexpectedFailure("Cannot read TModel for module \'<modName>\'\n<toString(ms.messages)>");
tmodels += convertTModel2PhysicalLocs(tm);
map[str, TModel] tmodels = ();
modsToDo = toSet(topModuleNames);
while ({str modName, *rest} := modsToDo) {
modsToDo = rest;
tm = getTModel(modName, ms);
tmodels[modName] = tm;
depNames = domain(tm.store[key_bom]);
modsToDo += depNames - domain(tmodels);
}
return tmodels;
return range(tmodels);
}
ProjectFiles preloadFiles(set[loc] workspaceFolders, loc cursorLoc) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ module lang::rascal::tests::rename::Performance
import lang::rascal::tests::rename::TestUtils;
import lang::rascal::lsp::refactor::Exception;

import lang::rascalcore::check::Checker;
import lang::rascalcore::check::RascalConfig;

import IO;
import List;
import util::Reflective;

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

@expected{unsupportedRename}
test bool failOnError() = testRename("int foo = x + y;");

test bool incrementalTypeCheck() {
procLoc = |memory://tests/incremental|;
pcfg = getTestPathConfig(procLoc);
procSrc = pcfg.srcs[0];

modName = "A";
moduleLoc = procSrc + "<modName>.rsc";
writeFile(moduleLoc, "module <modName>
'int foo() = 1;
'void main() { x = foo(); }
");

ms = rascalTModelForNames([modName], rascalCompilerConfig(pcfg), dummy_compile1);
res = testRenameOccurrences({byLoc(modName, moduleLoc, {0, 1})});
remove(procLoc);
return res;
}
42 changes: 28 additions & 14 deletions rascal-lsp/src/main/rascal/lang/rascal/tests/rename/TestUtils.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import util::Reflective;

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

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

Expand All @@ -68,10 +68,20 @@ private default DocumentEdit sortChanges(DocumentEdit e) = e;
private void verifyTypeCorrectRenaming(loc root, Edits edits, PathConfig pcfg) {
list[loc] editLocs = [l | /replace(l, _) := edits<0>];
assert size(editLocs) == size(toSet(editLocs)) : "Duplicate locations in suggested edits - VS Code cannot handle this";
// Back-up sources
loc backupLoc = |memory://tests/backup|;
remove(backupLoc, recursive = true);
copy(root, backupLoc, recursive = true);

executeDocumentEdits(sortEdits(edits<0>));
remove(pcfg.resources);
RascalCompilerConfig ccfg = rascalCompilerConfig(pcfg)[verbose = false][logPathConfig = false];
throwAnyErrors(checkAll(root, ccfg));

// Restore back-up
remove(root, recursive = true);
move(backupLoc, root, overwrite = true);
}

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

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

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

pcfg = getTestPathConfig(testDir);
modulesByLocation = {mByLoc | m <- modules, mByLoc := (m is byLoc ? m : byLoc(storeTestModule(testDir, m.name, m.body), m.nameOccs, newName = m.newName, skipCursors = m.skipCursors))};
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))};

for (byLoc(loc ml, _) <- modulesByLocation) {
for (m <- modulesByLocation) {
try {
parseModuleWithSpaces(ml);
parseModuleWithSpaces(m.file);
} catch _: {
throw "Parse error in test module <ml>";
}
}

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

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

for (success, src <- pcfg.srcs) {
verifyTypeCorrectRenaming(src, edits, pcfg);
if (success) {
verifyTypeCorrectRenaming(testDir, edits, pcfg);
}

remove(testDir);
if (!moduleExistsOnDisk) {
remove(testDir);
}
}

return success;
Expand Down Expand Up @@ -186,7 +200,7 @@ bool testRename(str stmtsStr, int cursorAtOldNameOccurrence = 0, str oldName = "
return false;
}

private PathConfig getTestPathConfig(loc testDir) {
public PathConfig getTestPathConfig(loc testDir) {
return pathConfig(
bin=testDir + "bin",
libs=[|lib://rascal|],
Expand Down

0 comments on commit 3841c86

Please sign in to comment.