Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve handling of qualified names when renaming #531

Merged
merged 65 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
126ed67
Prepare qualified names for renaming.
toinehartman Nov 19, 2024
3a333cc
Perform validity checks outside of changed file iteration.
toinehartman Nov 26, 2024
bd0cfbe
Implement renaming fully qualified names.
toinehartman Nov 26, 2024
26c531e
Fix bug where qualified prefix would be renamed based on length only.
toinehartman Nov 26, 2024
36801b1
Add self-qualified test.
toinehartman Nov 26, 2024
7656e0e
Do not support renaming external imports.
toinehartman Nov 27, 2024
9ae1b47
Implement Rascal workspace service.
toinehartman Nov 28, 2024
15e31d1
Implement Java-based will-rename-files callback.
toinehartman Nov 28, 2024
2ec68d7
Pair services in language server.
toinehartman Dec 2, 2024
9097412
Move module rename analysis from Java to Rascal.
toinehartman Dec 2, 2024
e816deb
Fix lint error.
toinehartman Dec 2, 2024
853b4fa
Fix import resolution when renaming module.
toinehartman Dec 4, 2024
8599a21
Escape qualified names, unescape file names.
toinehartman Dec 4, 2024
3178a19
Only consider imports in projects that can import the renamed module.
toinehartman Dec 4, 2024
73043b8
Use didRenameFiles callback.
toinehartman Dec 5, 2024
d4f5f5d
Fix code style.
toinehartman Dec 5, 2024
74818af
Add license.
toinehartman Dec 5, 2024
da8fb7c
UI test for renaming from explorer callback.
toinehartman Dec 6, 2024
18e5756
Move executor service to base class.
toinehartman Dec 9, 2024
55afe04
Only set file operation capabilities for Rascal.
toinehartman Dec 9, 2024
ae78cf5
Improve exception handling.
toinehartman Dec 9, 2024
a9e131d
Fix small review suggestions.
toinehartman Dec 9, 2024
390ae68
Move rename files callback to prevent multiple evaluators.
toinehartman Dec 9, 2024
17d7ff3
Fixes after PR review.
toinehartman Dec 9, 2024
573d26e
Use for loop instead of streaming.
toinehartman Dec 9, 2024
f4e1209
Reformat for readability.
toinehartman Dec 9, 2024
9961b23
Remove unused method.
toinehartman Dec 9, 2024
8f0db4e
Use tree from editor when possible.
toinehartman Dec 10, 2024
f46d65a
Fix LSP restart in loop.
toinehartman Dec 10, 2024
19ca3e4
Fix debug log message.
toinehartman Dec 10, 2024
f031b36
Simplify exceptions.
toinehartman Dec 10, 2024
bae99e5
Handle interrupt in Rascal callback.
toinehartman Dec 10, 2024
cdc4b22
Improve `readFile`
toinehartman Dec 11, 2024
4aab83d
Do all work inside futures.
toinehartman Dec 11, 2024
cf1e71d
Parallellize path config computation.
toinehartman Dec 11, 2024
947199e
Inline for readability.
toinehartman Dec 11, 2024
50e8a67
Fix indentation.
toinehartman Dec 11, 2024
48c95b5
Remove parse tree caching.
toinehartman Dec 12, 2024
efaeeb6
Fixes based on code review.
toinehartman Dec 16, 2024
e0c341d
UI test: open lib file before moving it.
toinehartman Dec 16, 2024
8df6aa6
Determine cursor tree again for renaming.
toinehartman Dec 16, 2024
37fc50a
Take screenshots to pin down test failure.
toinehartman Dec 17, 2024
d78a2ec
Open module even earlier so everything is visible in explorer.
toinehartman Dec 17, 2024
bbfa2b1
Fail earlier.
toinehartman Dec 17, 2024
cbbdd83
Log value of drap and drop targets.
toinehartman Dec 17, 2024
e93a8dd
Temporarily disable other tests.
toinehartman Dec 17, 2024
b9abd61
Use working method for moving files.
toinehartman Dec 18, 2024
cf76e51
Clean up test.
toinehartman Dec 18, 2024
8d3daa2
Check evaluators before normal rename test as well.
toinehartman Dec 18, 2024
b55976f
Take some screenshots to debug macOS.
toinehartman Dec 18, 2024
d38d331
More checks.
toinehartman Dec 18, 2024
ea6f7e1
Revert "Temporarily disable other tests."
toinehartman Dec 19, 2024
ab3fba4
Wait for context menu clicks.
toinehartman Dec 19, 2024
6969b5f
Try special approach for macOS.
toinehartman Dec 19, 2024
ea21fce
Fix rename test for macOS (special case)
sungshik Dec 20, 2024
da3c084
Clean up "renaming files works"
sungshik Dec 20, 2024
319664e
Remove unused import
sungshik Dec 20, 2024
a95c34b
Add missing semicolon
sungshik Dec 20, 2024
03cb83b
Clean up some unnecessary waits.
toinehartman Dec 20, 2024
7793bd0
Support folder renames and move code to Rascal.
toinehartman Dec 23, 2024
a262066
Handle empty failure reason.
toinehartman Dec 23, 2024
c81ff47
Explicitly pass executor.
toinehartman Dec 23, 2024
b3f0dc9
Clean up code.
toinehartman Dec 23, 2024
15c8587
Improve function name.
toinehartman Dec 23, 2024
15b4f52
Merge branch 'main' into fix/rename-refactoring/module-names
toinehartman Jan 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
import java.util.concurrent.ExecutorService;
import java.util.function.BiFunction;
import java.util.function.Function;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;
Expand Down Expand Up @@ -149,17 +152,23 @@ public void write(JsonWriter target, IValue value) throws IOException {
}

@SuppressWarnings({"java:S2189", "java:S106"})
public static void startLanguageServer(Supplier<IBaseTextDocumentService> service, int portNumber) {
public static void startLanguageServer(ExecutorService threadPool, Function<ExecutorService, IBaseTextDocumentService> docServiceProvider, BiFunction<ExecutorService, IBaseTextDocumentService, BaseWorkspaceService> workspaceServiceProvider, int portNumber) {
logger.info("Starting Rascal Language Server: {}", getVersion());

if (DEPLOY_MODE) {
startLSP(constructLSPClient(capturedIn, capturedOut, new ActualLanguageServer(() -> System.exit(0), service.get())));
var docService = docServiceProvider.apply(threadPool);
var wsService = workspaceServiceProvider.apply(threadPool, docService);
docService.pair(wsService);
startLSP(constructLSPClient(capturedIn, capturedOut, new ActualLanguageServer(() -> System.exit(0), docService, wsService)));
}
else {
try (ServerSocket serverSocket = new ServerSocket(portNumber, 0, InetAddress.getByName("127.0.0.1"))) {
logger.info("Rascal LSP server listens on port number: {}", portNumber);
while (true) {
startLSP(constructLSPClient(serverSocket.accept(), new ActualLanguageServer(() -> {}, service.get())));
var docService = docServiceProvider.apply(threadPool);
var wsService = workspaceServiceProvider.apply(threadPool, docService);
docService.pair(wsService);
startLSP(constructLSPClient(serverSocket.accept(), new ActualLanguageServer(() -> {}, docService, wsService)));
toinehartman marked this conversation as resolved.
Show resolved Hide resolved
}
} catch (IOException e) {
logger.fatal("Failure to start TCP server", e);
Expand Down Expand Up @@ -206,10 +215,10 @@ private static class ActualLanguageServer implements IBaseLanguageServerExtensi
private final Runnable onExit;
private IDEServicesConfiguration ideServicesConfiguration;

private ActualLanguageServer(Runnable onExit, IBaseTextDocumentService lspDocumentService) {
private ActualLanguageServer(Runnable onExit, IBaseTextDocumentService lspDocumentService, BaseWorkspaceService lspWorkspaceService) {
this.onExit = onExit;
this.lspDocumentService = lspDocumentService;
this.lspWorkspaceService = new BaseWorkspaceService(lspDocumentService);
this.lspWorkspaceService = lspWorkspaceService;
reg.registerLogical(new ProjectURIResolver(this::resolveProjectLocation));
reg.registerLogical(new TargetURIResolver(this::resolveProjectLocation));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;

import com.google.gson.JsonPrimitive;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.eclipse.lsp4j.ClientCapabilities;
Expand All @@ -50,13 +52,15 @@ public class BaseWorkspaceService implements WorkspaceService, LanguageClientAwa
public static final String RASCAL_META_COMMAND = "rascal-meta-command";
public static final String RASCAL_COMMAND = "rascal-command";

private final ExecutorService ownExecuter;

private final IBaseTextDocumentService documentService;
private final CopyOnWriteArrayList<WorkspaceFolder> workspaceFolders = new CopyOnWriteArrayList<>();


BaseWorkspaceService(IBaseTextDocumentService documentService) {
protected BaseWorkspaceService(ExecutorService exec, IBaseTextDocumentService documentService) {
this.documentService = documentService;
documentService.pair(this);
this.ownExecuter = exec;
}


Expand Down Expand Up @@ -120,6 +124,9 @@ public CompletableFuture<Object> executeCommand(ExecuteCommandParams params) {
}


protected final ExecutorService getExecuter() {
return ownExecuter;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@
*/
package org.rascalmpl.vscode.lsp;

import java.util.Set;
import java.util.concurrent.CompletableFuture;

import org.eclipse.lsp4j.RenameFilesParams;
import org.eclipse.lsp4j.ServerCapabilities;
import org.eclipse.lsp4j.services.LanguageClient;
import org.eclipse.lsp4j.services.TextDocumentService;
import org.rascalmpl.vscode.lsp.terminal.ITerminalIDEServer.LanguageParameter;
import org.rascalmpl.vscode.lsp.util.locations.LineColumnOffsetMap;

import io.usethesource.vallang.ISourceLocation;
import io.usethesource.vallang.IValue;

Expand All @@ -45,4 +49,5 @@ public interface IBaseTextDocumentService extends TextDocumentService {
CompletableFuture<IValue> executeCommand(String languageName, String command);
LineColumnOffsetMap getColumnMap(ISourceLocation file);

default void didRenameFiles(RenameFilesParams params, Set<ISourceLocation> workspaceFolders) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
*/
package org.rascalmpl.vscode.lsp.parametric;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.rascalmpl.vscode.lsp.BaseLanguageServer;
import org.rascalmpl.vscode.lsp.terminal.ITerminalIDEServer.LanguageParameter;

import com.google.gson.GsonBuilder;

public class ParametricLanguageServer extends BaseLanguageServer {
Expand All @@ -43,9 +43,10 @@ public static void main(String[] args) {
dedicatedLanguage = null;
}

startLanguageServer(() -> {
ExecutorService threadPool = Executors.newCachedThreadPool();
return new ParametricTextDocumentService(threadPool, dedicatedLanguage);
}, 9999);
startLanguageServer(Executors.newCachedThreadPool()
, threadPool -> new ParametricTextDocumentService(threadPool, dedicatedLanguage)
, ParametricWorkspaceService::new
, 9999
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public LineColumnOffsetMap getColumnMap(ISourceLocation file) {
return columns.get(file);
}

private String getContents(ISourceLocation file) {
public String getContents(ISourceLocation file) {
file = file.top();
TextDocumentState ideState = files.get(file);
if (ideState != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2018-2023, NWO-I CWI and Swat.engineering
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.rascalmpl.vscode.lsp.parametric;

import java.util.concurrent.ExecutorService;

import org.rascalmpl.vscode.lsp.BaseWorkspaceService;
import org.rascalmpl.vscode.lsp.IBaseTextDocumentService;

public class ParametricWorkspaceService extends BaseWorkspaceService {
ParametricWorkspaceService(ExecutorService exec, IBaseTextDocumentService docService) {
super(exec, docService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
*/
package org.rascalmpl.vscode.lsp.rascal;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.logging.log4j.LogManager;
Expand All @@ -36,10 +35,7 @@
public class RascalLanguageServer extends BaseLanguageServer {
public static void main(String[] args) {
try {
startLanguageServer(() -> {
ExecutorService threadPool = Executors.newCachedThreadPool();
return new RascalTextDocumentService(threadPool);
}, 8888);
startLanguageServer(Executors.newCachedThreadPool(), RascalTextDocumentService::new, RascalWorkspaceService::new, 8888);
}
catch (Throwable e) {
final Logger logger = LogManager.getLogger(RascalLanguageServer.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import java.io.IOException;
import java.io.StringReader;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand All @@ -43,29 +44,30 @@
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.FileRename;
import org.eclipse.lsp4j.jsonrpc.ResponseErrorException;
import org.eclipse.lsp4j.jsonrpc.messages.ResponseError;
import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode;
import org.rascalmpl.exceptions.Throw;
import org.rascalmpl.interpreter.Evaluator;
import org.rascalmpl.interpreter.env.ModuleEnvironment;
import org.rascalmpl.library.util.PathConfig;
import org.rascalmpl.uri.URIUtil;
import org.rascalmpl.values.IRascalValueFactory;
import org.rascalmpl.values.functions.IFunction;
import org.rascalmpl.values.parsetrees.ITree;
import org.rascalmpl.values.parsetrees.TreeAdapter;
import org.rascalmpl.vscode.lsp.BaseWorkspaceService;
import org.rascalmpl.vscode.lsp.IBaseLanguageClient;
import org.rascalmpl.vscode.lsp.RascalLSPMonitor;
import org.rascalmpl.vscode.lsp.TextDocumentState;
import org.rascalmpl.vscode.lsp.util.EvaluatorUtil;
import org.rascalmpl.vscode.lsp.util.RascalServices;
import org.rascalmpl.vscode.lsp.util.concurrent.InterruptibleFuture;
import org.rascalmpl.vscode.lsp.util.locations.ColumnMaps;
import org.rascalmpl.vscode.lsp.util.locations.Locations;

import io.usethesource.vallang.IConstructor;
import io.usethesource.vallang.IList;
Expand Down Expand Up @@ -205,11 +207,7 @@ public InterruptibleFuture<IList> getDocumentSymbols(IConstructor module) {
}


public InterruptibleFuture<ITuple> getRename(ITree module, Position cursor, Set<ISourceLocation> workspaceFolders, Function<ISourceLocation, PathConfig> getPathConfig, String newName, ColumnMaps columns) {
var moduleLocation = TreeAdapter.getLocation(module);
Position pos = Locations.toRascalPosition(moduleLocation, cursor, columns);
var cursorTree = TreeAdapter.locateLexical(module, pos.getLine(), pos.getCharacter());

public InterruptibleFuture<ITuple> getRename(ITree cursorTree, Set<ISourceLocation> workspaceFolders, Function<ISourceLocation, PathConfig> getPathConfig, String newName) {
return runEvaluator("Rascal rename", semanticEvaluator, eval -> {
try {
IFunction rascalGetPathConfig = eval.getFunctionValueFactory().function(getPathConfigType, (t, u) -> addResources(getPathConfig.apply((ISourceLocation) t[0])));
Expand All @@ -235,6 +233,36 @@ public InterruptibleFuture<ITuple> getRename(ITree module, Position cursor, Set<
}, VF.tuple(VF.list(), VF.map()), exec, false, client);
}

private ISourceLocation sourceLocationFromUri(String uri) {
DavyLandman marked this conversation as resolved.
Show resolved Hide resolved
try {
return URIUtil.createFromURI(uri);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}

public CompletableFuture<ITuple> getModuleRenames(List<FileRename> fileRenames, Set<ISourceLocation> workspaceFolders, Function<ISourceLocation, PathConfig> getPathConfig, Map<ISourceLocation, TextDocumentState> documents) {
var emptyResult = VF.tuple(VF.list(), VF.map());
if (fileRenames.isEmpty()) {
return CompletableFuture.completedFuture(emptyResult);
}

return CompletableFuture.supplyAsync(() -> fileRenames.stream()
.map(r -> VF.tuple(sourceLocationFromUri(r.getOldUri()), sourceLocationFromUri(r.getNewUri())))
.collect(VF.listWriter())
, exec)
.thenCompose(renames -> {
return runEvaluator("Rascal module rename", semanticEvaluator, eval -> {
IFunction rascalGetPathConfig = eval.getFunctionValueFactory().function(getPathConfigType, (t, u) -> addResources(getPathConfig.apply((ISourceLocation) t[0])));
try {
return (ITuple) eval.call("rascalRenameModule", renames, VF.set(workspaceFolders.toArray(ISourceLocation[]::new)), rascalGetPathConfig);
} catch (Throw e) {
throw new RuntimeException(e.getMessage());
}
}, emptyResult, exec, false, client).get();
});
}


public CompletableFuture<ITree> parseSourceFile(ISourceLocation loc, String input) {
return CompletableFuture.supplyAsync(() -> RascalServices.parseRascalModule(loc, input.toCharArray()), exec);
Expand Down
Loading
Loading