Switch Rewrite code action handler to JDT reconcilers
This commit is contained in:
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -14,12 +14,13 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
|||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
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.RewriteCodeActionHandler;
|
||||||
import org.springframework.ide.vscode.boot.java.rewrite.RewriteCompilationUnitCache;
|
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.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.RewriteRefactorings;
|
||||||
import org.springframework.ide.vscode.boot.java.rewrite.SpringBootUpgrade;
|
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.java.JavaProjectFinder;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||||
|
|
||||||
@@ -42,8 +43,8 @@ public class RewriteConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ConditionalOnBean(RewriteRecipeRepository.class)
|
@ConditionalOnBean(RewriteRecipeRepository.class)
|
||||||
@Bean RewriteCodeActionHandler rewriteCodeActionHandler(RewriteCompilationUnitCache cuCache, RewriteRecipeRepository recipeRepo, BootJavaConfig config) {
|
@Bean RewriteCodeActionHandler rewriteCodeActionHandler(CompilationUnitCache cuCache, BootJavaConfig config, JdtReconciler jdtReconciler, SimpleLanguageServer server) {
|
||||||
return new RewriteCodeActionHandler(cuCache, recipeRepo, config);
|
return new RewriteCodeActionHandler(cuCache, config, jdtReconciler, server.getQuickfixRegistry());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConditionalOnBean(RewriteRecipeRepository.class)
|
@ConditionalOnBean(RewriteRecipeRepository.class)
|
||||||
|
|||||||
@@ -24,24 +24,21 @@ import org.eclipse.lsp4j.CodeActionResolveSupportCapabilities;
|
|||||||
import org.eclipse.lsp4j.Command;
|
import org.eclipse.lsp4j.Command;
|
||||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.ide.vscode.boot.app.BootJavaConfig;
|
import org.springframework.ide.vscode.boot.app.BootJavaConfig;
|
||||||
import org.springframework.ide.vscode.boot.java.handlers.JavaCodeActionHandler;
|
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.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;
|
||||||
import org.springframework.ide.vscode.commons.languageserver.util.LspClient.Client;
|
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.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.IRegion;
|
||||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
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);
|
private static final Logger log = LoggerFactory.getLogger(RewriteCodeActionHandler.class);
|
||||||
|
|
||||||
final private RewriteCompilationUnitCache cuCache;
|
final private CompilationUnitCache cuCache;
|
||||||
final private RewriteRecipeRepository recipeRepo;
|
final private JdtReconciler jdtReconciler;
|
||||||
|
|
||||||
private BootJavaConfig config;
|
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.cuCache = cuCache;
|
||||||
this.recipeRepo = recipeRepo;
|
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
this.jdtReconciler = jdtReconciler;
|
||||||
|
this.quickfixRegistry = quickfixRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static boolean isResolve(CodeActionCapabilities capabilities, String property) {
|
protected static boolean isResolve(CodeActionCapabilities capabilities, String property) {
|
||||||
@@ -97,47 +97,33 @@ public class RewriteCodeActionHandler implements JavaCodeActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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());
|
|
||||||
|
|
||||||
|
URI uri = URI.create(doc.getUri());
|
||||||
if (isSupported(capabilities, context)) {
|
final QuickfixType rewriteFixType = quickfixRegistry.getQuickfixType(RewriteRefactorings.REWRITE_RECIPE_QUICKFIX);
|
||||||
CompilationUnit cu = cuCache.getCU(project, URI.create(doc.getUri()));
|
if (isSupported(capabilities, context) && rewriteFixType != null) {
|
||||||
if (cu != null) {
|
List<CodeAction> codeActions = cuCache.withCompilationUnit(project, uri, cu -> {
|
||||||
|
try {
|
||||||
cu = recipeRepo.mark(project, descriptors, cu);
|
List<CodeAction> cas = new ArrayList<>();
|
||||||
|
List<ReconcileProblem> problems = new ArrayList<>();
|
||||||
List<CodeAction> codeActions = new ArrayList<>();
|
BasicProblemCollector problemsCollector = new BasicProblemCollector(problems);
|
||||||
new JavaIsoVisitor<ExecutionContext>() {
|
jdtReconciler.reconcile(project, uri, cu, problemsCollector, true);
|
||||||
public J visit(Tree tree, ExecutionContext ctx) {
|
for (ReconcileProblem p : problems) {
|
||||||
if (tree == null) {
|
if (p.getOffset() <= region.getOffset() && p.getOffset() + p.getLength() >= region.getOffset() + region.getLength()) {
|
||||||
return null;
|
for (QuickfixData<?> qf : p.getQuickfixes()) {
|
||||||
}
|
if (qf.params instanceof FixDescriptor) {
|
||||||
if (tree instanceof J) {
|
cas.add(createCodeActionFromScope((FixDescriptor) qf.params));
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return super.visit(tree, ctx);
|
|
||||||
} else {
|
|
||||||
return (J) tree;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (J) tree;
|
}
|
||||||
};
|
return cas;
|
||||||
}.visitNonNull(cu, new InMemoryExecutionContext());
|
} catch (Exception e) {
|
||||||
return codeActions.stream().map(ca -> Either.<Command, CodeAction>forRight(ca)).collect(Collectors.toList());
|
log.error("", e);
|
||||||
}
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
});
|
||||||
|
|
||||||
|
return codeActions.stream().map(ca -> Either.<Command, CodeAction>forRight(ca)).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("", e);
|
log.error("", e);
|
||||||
@@ -145,18 +131,7 @@ public class RewriteCodeActionHandler implements JavaCodeActionHandler {
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeAction[] createCodeActions(IDocument doc, FixAssistMarker m, J astNode) {
|
private CodeAction createCodeActionFromScope(FixDescriptor d) {
|
||||||
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) {
|
|
||||||
CodeAction ca = new CodeAction();
|
CodeAction ca = new CodeAction();
|
||||||
ca.setKind(CodeActionKind.Refactor);
|
ca.setKind(CodeActionKind.Refactor);
|
||||||
ca.setTitle(d.getLabel());
|
ca.setTitle(d.getLabel());
|
||||||
|
|||||||
Reference in New Issue
Block a user