From 9dc8e7d78a7a3fa288877535036aaab13d565b73 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Wed, 4 Dec 2024 18:36:48 +0100 Subject: [PATCH] Only consider imports in projects that can import the renamed module. --- .../lsp/rascal/RascalLanguageServices.java | 21 +++++----- .../lsp/rascal/RascalWorkspaceService.java | 28 ------------- .../lang/rascal/lsp/refactor/Rename.rsc | 4 +- .../rascal/lsp/refactor/rename/Modules.rsc | 40 +++++++++++-------- 4 files changed, 37 insertions(+), 56 deletions(-) diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalLanguageServices.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalLanguageServices.java index 7dd57257..543631e3 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalLanguageServices.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalLanguageServices.java @@ -46,7 +46,6 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.Nullable; @@ -75,7 +74,6 @@ import io.usethesource.vallang.IConstructor; import io.usethesource.vallang.IList; -import io.usethesource.vallang.IMap; import io.usethesource.vallang.ISet; import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IString; @@ -256,13 +254,13 @@ private Optional findContainingWorkspaceFolder(ISourceLocation .findFirst(); } - private IMap qualfiedNameChangesFromRenames(List renames, Set workspaceFolders, Function getPathConfig) { + private ISet qualfiedNameChangesFromRenames(List renames, Set workspaceFolders, Function getPathConfig) { // Sort workspace folders so we get the most specific folders first List sortedWorkspaceFolders = workspaceFolders.stream() .sorted((o1, o2) -> o1.toString().compareTo(o2.toString())) .collect(Collectors.toList()); - Map nameMapping = renames.stream() + Set nameMapping = renames.stream() .map(rename -> { ISourceLocation currentLoc = sourceLocationFromUri(rename.getOldUri()); ISourceLocation newLoc = sourceLocationFromUri(rename.getNewUri()); @@ -289,24 +287,27 @@ private IMap qualfiedNameChangesFromRenames(List renames, Set getModuleRenames(List fileRenames, Set workspaceFolders, Function getPathConfig) { - final IMap qualifiedNameChanges = qualfiedNameChangesFromRenames(fileRenames, workspaceFolders, getPathConfig); + if (fileRenames.isEmpty()) return InterruptibleFuture.completedFuture(null); + + final ISet qualifiedNameChanges = qualfiedNameChangesFromRenames(fileRenames, workspaceFolders, getPathConfig); try { return runEvaluator("Rascal module rename", semanticEvaluator, eval -> { - return (ITuple) eval.call("rascalRenameModule", qualifiedNameChanges, VF.set(workspaceFolders.toArray(ISourceLocation[]::new))); + IFunction rascalGetPathConfig = eval.getFunctionValueFactory().function(getPathConfigType, (t, u) -> addResources(getPathConfig.apply((ISourceLocation) t[0]))); + return (ITuple) eval.call("rascalRenameModule", qualifiedNameChanges, VF.set(workspaceFolders.toArray(ISourceLocation[]::new)), rascalGetPathConfig); }, VF.tuple(VF.list(), VF.map()), exec, false, client); } catch (Throw e) { if (e.getException() instanceof IConstructor) { diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalWorkspaceService.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalWorkspaceService.java index a9d4a15e..371c4b24 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalWorkspaceService.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalWorkspaceService.java @@ -26,20 +26,12 @@ */ package org.rascalmpl.vscode.lsp.rascal; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.stream.Collectors; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @@ -48,40 +40,20 @@ import org.eclipse.lsp4j.FileOperationFilter; import org.eclipse.lsp4j.FileOperationOptions; import org.eclipse.lsp4j.FileOperationPattern; -import org.eclipse.lsp4j.FileRename; -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.RenameFilesParams; -import org.eclipse.lsp4j.ResourceOperation; import org.eclipse.lsp4j.ServerCapabilities; -import org.eclipse.lsp4j.TextDocumentEdit; -import org.eclipse.lsp4j.TextEdit; -import org.eclipse.lsp4j.VersionedTextDocumentIdentifier; import org.eclipse.lsp4j.WorkspaceEdit; import org.eclipse.lsp4j.WorkspaceFolder; -import org.eclipse.lsp4j.jsonrpc.ResponseErrorException; -import org.eclipse.lsp4j.jsonrpc.messages.Either; -import org.eclipse.lsp4j.jsonrpc.messages.ResponseError; -import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode; import org.eclipse.lsp4j.services.LanguageClient; -import org.rascalmpl.library.util.PathConfig; -import org.rascalmpl.uri.URIUtil; -import org.rascalmpl.values.parsetrees.ITree; -import org.rascalmpl.values.parsetrees.ProductionAdapter; -import org.rascalmpl.values.parsetrees.TreeAdapter; -import org.rascalmpl.values.parsetrees.visitors.IdentityTreeVisitor; import org.rascalmpl.vscode.lsp.BaseWorkspaceService; import org.rascalmpl.vscode.lsp.IBaseLanguageClient; import org.rascalmpl.vscode.lsp.IBaseTextDocumentService; -import org.rascalmpl.vscode.lsp.TextDocumentState; import org.rascalmpl.vscode.lsp.rascal.model.FileFacts; import org.rascalmpl.vscode.lsp.util.DocumentChanges; -import org.rascalmpl.vscode.lsp.util.Versioned; import org.rascalmpl.vscode.lsp.util.locations.ColumnMaps; import org.rascalmpl.vscode.lsp.util.locations.Locations; import io.usethesource.vallang.ISourceLocation; -import io.usethesource.vallang.IValue; public class RascalWorkspaceService extends BaseWorkspaceService { private static final Logger logger = LogManager.getLogger(RascalWorkspaceService.class); diff --git a/rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/Rename.rsc b/rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/Rename.rsc index d60387bb..d12ce9c9 100644 --- a/rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/Rename.rsc +++ b/rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/Rename.rsc @@ -657,8 +657,8 @@ Edits rascalRenameSymbol(Tree cursorT, set[loc] workspaceFolders, str newName, P return ; }, totalWork = 7); -Edits rascalRenameModule(map[str, str] qualifiedNameChanges, set[loc] workspaceFolders) = - propagateModuleRenames(qualifiedNameChanges, workspaceFolders); +Edits rascalRenameModule(rel[str oldName, str newName, PathConfig pcfg] qualifiedNameChanges, set[loc] workspaceFolders, PathConfig(loc) getPathConfig) = + propagateModuleRenames(qualifiedNameChanges, workspaceFolders, getPathConfig); //// WORKAROUNDS diff --git a/rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/rename/Modules.rsc b/rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/rename/Modules.rsc index 66d29fab..57e6ca91 100644 --- a/rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/rename/Modules.rsc +++ b/rascal-lsp/src/main/rascal/lang/rascal/lsp/refactor/rename/Modules.rsc @@ -13,8 +13,7 @@ import Set; import String; import util::FileSystem; - -data PathConfig; +import util::Reflective; private tuple[str, loc] fullQualifiedName(QualifiedName qn) = <"", qn.src>; private tuple[str, loc] qualifiedPrefix(QualifiedName qn) { @@ -28,31 +27,40 @@ private tuple[str, loc] qualifiedPrefix(QualifiedName qn) { return ; } -list[TextEdit] getChanges(loc f, map[str, str] qualifiedNameChanges) { +private bool isReachable(PathConfig toProject, PathConfig fromProject) = + toProject == fromProject // Both configs belong to the same project + || toProject.bin in fromProject.libs; // The using project can import the declaring project + +list[TextEdit] getChanges(loc f, PathConfig wsProject, rel[str oldName, str newName, PathConfig pcfg] qualifiedNameChanges) { list[TextEdit] changes = []; start[Module] m = parseModuleWithSpacesCached(f); for (/QualifiedName qn := m) { - if ( := fullQualifiedName(qn), fullName in qualifiedNameChanges) { - changes += replace(fullLoc, qualifiedNameChanges[fullName]); - } else if ( := qualifiedPrefix(qn), namePrefix in qualifiedNameChanges) { - changes += replace(prefixLoc, qualifiedNameChanges[namePrefix]); + for ( <- {fullQualifiedName(qn), qualifiedPrefix(qn)} + , {} := qualifiedNameChanges[oldName] + , isReachable(projWithRenamedMod, wsProject) + ) { + changes += replace(l, newName); } } return changes; } -Edits propagateModuleRenames(map[str, str] qualifiedNameChanges, set[loc] workspaceFolders) { - set[loc] wsFiles = flatMap(workspaceFolders, set[loc](loc wsFolder) { - return find(wsFolder, "rsc"); - }); +Edits propagateModuleRenames(rel[str oldName, str newName, PathConfig pcfg] qualifiedNameChanges, set[loc] workspaceFolders, PathConfig(loc) getPathConfig) { + set[PathConfig] projectWithRenamedModule = qualifiedNameChanges.pcfg; + set[DocumentEdit] edits = flatMap(workspaceFolders, set[DocumentEdit](loc wsFolder) { + PathConfig wsFolderPcfg = getPathConfig(wsFolder); - set[DocumentEdit] edits = {changed(file, changes) - | loc file <- wsFiles - , changes := getChanges(file, qualifiedNameChanges) - , changes != [] - }; + // If this workspace cannot reach any of the renamed modules, no need to continue looking for references to renamed modules here at all + if (!any(PathConfig changedProj <- projectWithRenamedModule, isReachable(changedProj, wsFolderPcfg))) return {}; + + return {changed(file, changes) + | loc file <- find(wsFolder, "rsc") + , changes := getChanges(file, wsFolderPcfg, qualifiedNameChanges) + , changes != [] + }; + }); return ; }