Switch Rewrite code action handler to JDT reconcilers

This commit is contained in:
aboyko
2023-08-15 20:49:11 -04:00
parent c62f683f76
commit 8666ef9785
3 changed files with 78 additions and 66 deletions

View File

@@ -0,0 +1,36 @@
/*******************************************************************************
* Copyright (c) 2022, 2023 VMware, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.languageserver.reconcile;
import java.util.Collection;
public class BasicProblemCollector implements IProblemCollector {
private final Collection<ReconcileProblem> problems;
public BasicProblemCollector(Collection<ReconcileProblem> problems) {
this.problems = problems;
}
@Override
public void beginCollecting() {
}
@Override
public void endCollecting() {
}
@Override
public void accept(ReconcileProblem problem) {
problems.add(problem);
}
}

View File

@@ -14,12 +14,13 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ide.vscode.boot.java.reconcilers.JdtReconciler;
import org.springframework.ide.vscode.boot.java.rewrite.RewriteCodeActionHandler;
import org.springframework.ide.vscode.boot.java.rewrite.RewriteCompilationUnitCache;
import org.springframework.ide.vscode.boot.java.rewrite.RewriteRecipeRepository;
import org.springframework.ide.vscode.boot.java.rewrite.RewriteReconciler;
import org.springframework.ide.vscode.boot.java.rewrite.RewriteRefactorings;
import org.springframework.ide.vscode.boot.java.rewrite.SpringBootUpgrade;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
@@ -42,8 +43,8 @@ public class RewriteConfig {
}
@ConditionalOnBean(RewriteRecipeRepository.class)
@Bean RewriteCodeActionHandler rewriteCodeActionHandler(RewriteCompilationUnitCache cuCache, RewriteRecipeRepository recipeRepo, BootJavaConfig config) {
return new RewriteCodeActionHandler(cuCache, recipeRepo, config);
@Bean RewriteCodeActionHandler rewriteCodeActionHandler(CompilationUnitCache cuCache, BootJavaConfig config, JdtReconciler jdtReconciler, SimpleLanguageServer server) {
return new RewriteCodeActionHandler(cuCache, config, jdtReconciler, server.getQuickfixRegistry());
}
@ConditionalOnBean(RewriteRecipeRepository.class)

View File

@@ -24,24 +24,21 @@ import org.eclipse.lsp4j.CodeActionResolveSupportCapabilities;
import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.openrewrite.ExecutionContext;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.Tree;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.CompilationUnit;
import org.openrewrite.marker.Range;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.app.BootJavaConfig;
import org.springframework.ide.vscode.boot.java.handlers.JavaCodeActionHandler;
import org.springframework.ide.vscode.boot.java.reconcilers.JdtReconciler;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.quickfix.Quickfix.QuickfixData;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.BasicProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
import org.springframework.ide.vscode.commons.languageserver.util.LspClient;
import org.springframework.ide.vscode.commons.languageserver.util.LspClient.Client;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeCodeActionDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.FixAssistMarker;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -49,15 +46,18 @@ public class RewriteCodeActionHandler implements JavaCodeActionHandler {
private static final Logger log = LoggerFactory.getLogger(RewriteCodeActionHandler.class);
final private RewriteCompilationUnitCache cuCache;
final private RewriteRecipeRepository recipeRepo;
final private CompilationUnitCache cuCache;
final private JdtReconciler jdtReconciler;
private BootJavaConfig config;
public RewriteCodeActionHandler(RewriteCompilationUnitCache cuCache, RewriteRecipeRepository recipeRepo, BootJavaConfig config) {
private QuickfixRegistry quickfixRegistry;
public RewriteCodeActionHandler(CompilationUnitCache cuCache, BootJavaConfig config, JdtReconciler jdtReconciler, QuickfixRegistry quickfixRegistry) {
this.cuCache = cuCache;
this.recipeRepo = recipeRepo;
this.config = config;
this.jdtReconciler = jdtReconciler;
this.quickfixRegistry = quickfixRegistry;
}
protected static boolean isResolve(CodeActionCapabilities capabilities, String property) {
@@ -97,47 +97,33 @@ public class RewriteCodeActionHandler implements JavaCodeActionHandler {
}
try {
List<RecipeCodeActionDescriptor> descriptors = recipeRepo.getCodeActionRecipeDescriptors().stream()
// If Recipe not present - don't show quick assist as it won't be handled without the Rewrite recipe present
.filter(d -> d.isApplicable(project))
.collect(Collectors.toList());
if (isSupported(capabilities, context)) {
CompilationUnit cu = cuCache.getCU(project, URI.create(doc.getUri()));
if (cu != null) {
cu = recipeRepo.mark(project, descriptors, cu);
List<CodeAction> codeActions = new ArrayList<>();
new JavaIsoVisitor<ExecutionContext>() {
public J visit(Tree tree, ExecutionContext ctx) {
if (tree == null) {
return null;
}
if (tree instanceof J) {
J node = (J) tree;
Range range = node.getMarkers().findFirst(Range.class).orElse(null);
if (range != null
&& range.getStart().getOffset() <= region.getOffset()
&& region.getOffset() + region.getLength() <= range.getEnd().getOffset()) {
for (FixAssistMarker m : node.getMarkers().findAll(FixAssistMarker.class)) {
for (CodeAction ca : createCodeActions(doc, m, node)) {
codeActions.add(ca);
}
URI uri = URI.create(doc.getUri());
final QuickfixType rewriteFixType = quickfixRegistry.getQuickfixType(RewriteRefactorings.REWRITE_RECIPE_QUICKFIX);
if (isSupported(capabilities, context) && rewriteFixType != null) {
List<CodeAction> codeActions = cuCache.withCompilationUnit(project, uri, cu -> {
try {
List<CodeAction> cas = new ArrayList<>();
List<ReconcileProblem> problems = new ArrayList<>();
BasicProblemCollector problemsCollector = new BasicProblemCollector(problems);
jdtReconciler.reconcile(project, uri, cu, problemsCollector, true);
for (ReconcileProblem p : problems) {
if (p.getOffset() <= region.getOffset() && p.getOffset() + p.getLength() >= region.getOffset() + region.getLength()) {
for (QuickfixData<?> qf : p.getQuickfixes()) {
if (qf.params instanceof FixDescriptor) {
cas.add(createCodeActionFromScope((FixDescriptor) qf.params));
}
return super.visit(tree, ctx);
} else {
return (J) tree;
}
}
return (J) tree;
};
}.visitNonNull(cu, new InMemoryExecutionContext());
return codeActions.stream().map(ca -> Either.<Command, CodeAction>forRight(ca)).collect(Collectors.toList());
}
}
return cas;
} catch (Exception e) {
log.error("", e);
}
return Collections.emptyList();
});
return codeActions.stream().map(ca -> Either.<Command, CodeAction>forRight(ca)).collect(Collectors.toList());
}
} catch (Exception e) {
log.error("", e);
@@ -145,18 +131,7 @@ public class RewriteCodeActionHandler implements JavaCodeActionHandler {
return Collections.emptyList();
}
private CodeAction[] createCodeActions(IDocument doc, FixAssistMarker m, J astNode) {
if (astNode != null) {
return m.getFixes().stream()
.filter(d -> recipeRepo.getRecipe(d.getRecipeId()) != null)
.map(d -> createCodeActionFromScope(doc, d))
.toArray(CodeAction[]::new);
}
return new CodeAction[0];
}
private CodeAction createCodeActionFromScope(IDocument doc,
FixDescriptor d) {
private CodeAction createCodeActionFromScope(FixDescriptor d) {
CodeAction ca = new CodeAction();
ca.setKind(CodeActionKind.Refactor);
ca.setTitle(d.getLabel());