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

Show quick fix to rename references for modifying symbol name manually #2487

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -383,4 +383,17 @@ public static IMarker createWarningMarker(String type, IResource resource, Strin
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
return marker;
}

/**
* Creates a simple info marker with the given type, id and status message to the given resource.
*/
public static IMarker createInfoMarker(String type, IResource resource, String message, int id, int start, int end) throws CoreException {
IMarker marker = resource.createMarker(type);
marker.setAttribute(IJavaModelMarker.ID, id);
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO);
marker.setAttribute(IMarker.CHAR_START, start);
marker.setAttribute(IMarker.CHAR_END, end);
return marker;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ private CorrectionMessages() {
public static String LocalCorrectionsSubProcessor_hiding_field_label;
public static String LocalCorrectionsSubProcessor_rename_var_label;
public static String LocalCorrectionsSubProcessor_hiding_argument_label;
public static String LocalCorrectionsSubProcessor_manual_rename_label;
public static String LocalCorrectionsSubProcessor_setparenteses_description;
public static String LocalCorrectionsSubProcessor_setparenteses_instanceof_description;
public static String LocalCorrectionsSubProcessor_InferGenericTypeArguments;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ LocalCorrectionsSubProcessor_hiding_local_label=Rename local variable ''{0}''
LocalCorrectionsSubProcessor_hiding_field_label=Rename field ''{0}''
LocalCorrectionsSubProcessor_rename_var_label=Rename ''{0}''
LocalCorrectionsSubProcessor_hiding_argument_label=Rename argument ''{0}''
LocalCorrectionsSubProcessor_manual_rename_label=Rename usages of ''{0}'' to ''{1}''
LocalCorrectionsSubProcessor_setparenteses_description=Put ''{0}'' expression in parentheses
LocalCorrectionsSubProcessor_InferGenericTypeArguments=Infer Generic Type Arguments...
LocalCorrectionsSubProcessor_InferGenericTypeArguments_description=Start the 'Infer Generic Type Arguments' refactoring
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
import org.eclipse.jdt.ls.core.internal.corrections.proposals.ReplaceCorrectionProposal;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.TypeMismatchSubProcessor;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.UnresolvedElementsSubProcessor;
import org.eclipse.jdt.ls.core.internal.handlers.BaseDocumentLifeCycleHandler;
import org.eclipse.jdt.ls.core.internal.handlers.DocumentLifeCycleHandler;
import org.eclipse.jdt.ls.core.internal.handlers.OrganizeImportsHandler;
import org.eclipse.jdt.ls.core.internal.text.correction.ModifierCorrectionSubProcessor;
import org.eclipse.lsp4j.CodeActionKind;
Expand All @@ -75,7 +77,7 @@ private static int moveBack(int offset, int start, String ignoreCharacters, ICom
return start;
}

public List<ChangeCorrectionProposal> getCorrections(CodeActionParams params, IInvocationContext context, IProblemLocationCore[] locations) throws CoreException {
public List<ChangeCorrectionProposal> getCorrections(CodeActionParams params, IInvocationContext context, IProblemLocationCore[] locations, DocumentLifeCycleHandler documentLifeCycleHandler) throws CoreException {
if (locations == null || locations.length == 0) {
return Collections.emptyList();
}
Expand All @@ -84,7 +86,7 @@ public List<ChangeCorrectionProposal> getCorrections(CodeActionParams params, II
for (int i = 0; i < locations.length; i++) {
IProblemLocationCore curr = locations[i];
if (handledProblems(curr, locations, handledProblems)) {
process(params, context, curr, resultingCollections);
process(params, context, curr, resultingCollections, documentLifeCycleHandler);
}
}
return resultingCollections;
Expand All @@ -107,7 +109,7 @@ private static boolean handledProblems(IProblemLocationCore location, IProblemLo
return handledProblems.add(problemId);
}

private void process(CodeActionParams params, IInvocationContext context, IProblemLocationCore problem, Collection<ChangeCorrectionProposal> proposals) throws CoreException {
private void process(CodeActionParams params, IInvocationContext context, IProblemLocationCore problem, Collection<ChangeCorrectionProposal> proposals, DocumentLifeCycleHandler documentLifeCycleHandler) throws CoreException {
int id = problem.getProblemId();
if (id == 0) { // no proposals for none-problem locations
return;
Expand Down Expand Up @@ -668,7 +670,9 @@ private void process(CodeActionParams params, IInvocationContext context, IProbl
// TypeAnnotationSubProcessor.addMoveTypeAnnotationToTypeProposal(context,
// problem, proposals);
// break;

case BaseDocumentLifeCycleHandler.RENAME_REFERENCE_PROBLEM_ID:
LocalCorrectionsSubProcessor.getManualRenameCorrectionProposals(context, problem, proposals, documentLifeCycleHandler);
break;
default:
String str = problem.toString();
System.out.println(str);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@
package org.eclipse.jdt.ls.core.internal.corrections.proposals;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IType;
Expand Down Expand Up @@ -101,7 +105,9 @@
import org.eclipse.jdt.internal.ui.fix.UnnecessaryCodeCleanUpCore;
import org.eclipse.jdt.internal.ui.text.correction.IProblemLocationCore;
import org.eclipse.jdt.internal.ui.util.ASTHelper;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.Messages;
import org.eclipse.jdt.ls.core.internal.corext.refactoring.surround.ExceptionAnalyzer;
import org.eclipse.jdt.ls.core.internal.corext.refactoring.surround.SurroundWithTryCatchRefactoring;
import org.eclipse.jdt.ls.core.internal.corrections.CorrectionMessages;
Expand All @@ -111,13 +117,18 @@
import org.eclipse.jdt.ls.core.internal.corrections.proposals.ChangeMethodSignatureProposal.ChangeDescription;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.ChangeMethodSignatureProposal.InsertDescription;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.ChangeMethodSignatureProposal.RemoveDescription;
import org.eclipse.jdt.ls.core.internal.handlers.BaseDocumentLifeCycleHandler;
import org.eclipse.jdt.ls.core.internal.handlers.DocumentLifeCycleHandler;
import org.eclipse.jdt.ls.core.internal.text.correction.CUCorrectionCommandProposal;
import org.eclipse.jdt.ls.core.internal.text.correction.ModifierCorrectionSubProcessor;
import org.eclipse.jdt.ls.core.internal.text.correction.QuickAssistProcessor;
import org.eclipse.lsp4j.CodeActionKind;
import org.eclipse.lsp4j.Range;

public class LocalCorrectionsSubProcessor {

private static final String ADD_STATIC_ACCESS_ID = "org.eclipse.jdt.ui.correction.changeToStatic"; //$NON-NLS-1$
private static final String RENAME_REFERENCES_COMMAND = "java.action.renameReferences";

public static void addUncaughtExceptionProposals(IInvocationContext context, IProblemLocationCore problem, Collection<ChangeCorrectionProposal> proposals) throws CoreException {
ICompilationUnit cu = context.getCompilationUnit();
Expand Down Expand Up @@ -1109,4 +1120,33 @@ public static void addValueForAnnotationProposals(IInvocationContext context, IP
}
}

public static void getManualRenameCorrectionProposals(IInvocationContext context, IProblemLocationCore problem, Collection<ChangeCorrectionProposal> proposals, DocumentLifeCycleHandler documentLifeCycleHandler) throws CoreException {
if (!JavaLanguageServerPlugin.getPreferencesManager().getPreferences().getRenameReferencesEnabled()) {
return;
}
ICompilationUnit cu = context.getCompilationUnit();
if (cu == null) {
return;
}
IResource resource = cu.getResource();
if (resource == null) {
return;
}
IMarker[] markers = resource.findMarkers(BaseDocumentLifeCycleHandler.RENAME_REFERENCE_MARKER_ID, false, IResource.DEPTH_ONE);
Arrays.stream(markers).forEach(marker -> {
try {
if (Objects.equals(problem.getOffset(), marker.getAttribute(IMarker.CHAR_START)) && Objects.equals(problem.getOffset() + problem.getLength(), marker.getAttribute(IMarker.CHAR_END))) {
String originalName = (String) marker.getAttribute("originalName");
String newName = (String) marker.getAttribute("newName");
Range range = JDTUtils.toRange(cu, problem.getOffset(), problem.getLength());
if (originalName != null && newName != null) {
String label = Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_manual_rename_label, new String[]{ originalName, newName });
proposals.add(new CUCorrectionCommandProposal(label, CodeActionKind.QuickFix, cu, IProposalRelevance.RENAME_REFACTORING_QUICK_FIX, RENAME_REFERENCES_COMMAND, Arrays.asList(cu.getResource().getLocationURI().toString(), originalName, newName, range)));
}
}
} catch (CoreException e) {
// Do nothing
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,30 @@
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModelMarker;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IProblemRequestor;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.manipulation.CoreASTProvider;
import org.eclipse.jdt.internal.core.OpenableElementInfo;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.ls.core.internal.DocumentAdapter;
import org.eclipse.jdt.ls.core.internal.IConstants;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.JobHelpers;
import org.eclipse.jdt.ls.core.internal.Messages;
import org.eclipse.jdt.ls.core.internal.MovingAverage;
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
import org.eclipse.jdt.ls.core.internal.ResourceUtils;
import org.eclipse.jdt.ls.core.internal.corrections.CorrectionMessages;
import org.eclipse.jdt.ls.core.internal.corrections.DiagnosticsHelper;
import org.eclipse.jdt.ls.core.internal.managers.InvisibleProjectImporter;
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;
Expand Down Expand Up @@ -103,6 +111,9 @@ public abstract class BaseDocumentLifeCycleHandler {
*/
private static final long PUBLISH_DIAGNOSTICS_MAX_DEBOUNCE = 2000; /*ms*/

public static final String RENAME_REFERENCE_MARKER_ID = IConstants.PLUGIN_ID + ".renameReferenceMarker";
public static final int RENAME_REFERENCE_PROBLEM_ID = IProblem.Syntax + 2000;

private CoreASTProvider sharedASTProvider;
private WorkspaceJob validationTimer;
private WorkspaceJob publishDiagnosticsJob;
Expand All @@ -111,6 +122,9 @@ public abstract class BaseDocumentLifeCycleHandler {
private MovingAverage movingAverageForValidation = new MovingAverage(DOCUMENT_LIFECYCLE_MAX_DEBOUNCE);
private MovingAverage movingAverageForDiagnostics = new MovingAverage(PUBLISH_DIAGNOSTICS_MIN_DEBOUNCE);

private Map<String, List<MemberInfo>> documentMemberInfos = new HashMap<>();
private Map<String, List<IMarker>> documentMarkers = new HashMap<>();

public BaseDocumentLifeCycleHandler(boolean delayValidation) {
this.sharedASTProvider = CoreASTProvider.getInstance();
if (delayValidation) {
Expand Down Expand Up @@ -303,11 +317,18 @@ public IProblemRequestor getProblemRequestor(ICompilationUnit workingCopy) {

};
int flags = ICompilationUnit.FORCE_PROBLEM_DETECTION | ICompilationUnit.ENABLE_BINDINGS_RECOVERY | ICompilationUnit.ENABLE_STATEMENTS_RECOVERY;
if (JavaLanguageServerPlugin.getPreferencesManager().getPreferences().getRenameReferencesEnabled()) {
provideRenameReferencesMarkers(unit);
}
unit.reconcile(ICompilationUnit.NO_AST, flags, wcOwner, monitor);
}

public void didClose(DidCloseTextDocumentParams params) {
documentVersions.remove(params.getTextDocument().getUri());
ICompilationUnit cu = JDTUtils.resolveCompilationUnit(params.getTextDocument().getUri());
if (cu != null) {
this.documentMemberInfos.remove(cu.getResource().getLocationURI().toString());
}
ISchedulingRule rule = JDTUtils.getRule(params.getTextDocument().getUri());
try {
ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() {
Expand Down Expand Up @@ -410,6 +431,9 @@ public ICompilationUnit handleOpen(DidOpenTextDocumentParams params) {
// see https://github.com/redhat-developer/vscode-java/issues/274
checkPackageDeclaration(uri, unit);
inferInvisibleProjectSourceRoot(unit);
if (JavaLanguageServerPlugin.getPreferencesManager().getPreferences().getRenameReferencesEnabled()) {
this.documentMemberInfos.put(unit.getResource().getLocationURI().toString(), this.getMemberInfos(unit));
}
} catch (JavaModelException e) {
JavaLanguageServerPlugin.logException("Error while opening document. URI: " + uri, e);
}
Expand Down Expand Up @@ -467,6 +491,87 @@ public ICompilationUnit handleChanged(DidChangeTextDocumentParams params) {
return unit;
}

private void provideRenameReferencesMarkers(ICompilationUnit unit) {
String uri = unit.getResource().getLocationURI().toString();
List<MemberInfo> memberInfos = this.getMemberInfos(unit);
try {
if (this.documentMemberInfos.containsKey(uri)) {
// delete existing markers
List<IMarker> currentMarkers = this.documentMarkers.get(uri);
if (currentMarkers != null) {
unit.getResource().deleteMarkers(RENAME_REFERENCE_MARKER_ID, false, IResource.DEPTH_ONE);
currentMarkers.clear();
} else {
currentMarkers = new ArrayList<>();
this.documentMarkers.put(uri, currentMarkers);
}
List<MemberInfo> cacheMemberInfos = this.documentMemberInfos.get(uri);
if (cacheMemberInfos.size() == memberInfos.size()) {
for (int i = 0; i < memberInfos.size(); i++) {
MemberInfo memberInfo = memberInfos.get(i);
String name = memberInfo.getName();
MemberInfo cacheMemberInfo = cacheMemberInfos.get(i);
if (name == null) {
this.documentMemberInfos.put(uri, memberInfos);
break;
}
if (cacheMemberInfo.getName().equals(name)) {
continue;
}
String message = Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_manual_rename_label, new String[]{ cacheMemberInfo.getName(), name });
IMarker marker = ResourceUtils.createInfoMarker(RENAME_REFERENCE_MARKER_ID, unit.getResource(), message, RENAME_REFERENCE_PROBLEM_ID, memberInfo.getNameRange().getOffset(), memberInfo.getNameRange().getOffset() + memberInfo.getNameRange().getLength());
marker.setAttribute("originalName", cacheMemberInfo.getName());
marker.setAttribute("newName", name);
currentMarkers.add(marker);
}
} else {
// update the storage names list
this.documentMemberInfos.put(uri, memberInfos);
}
} else {
// initialize the storage names list
this.documentMemberInfos.put(uri, memberInfos);
}
} catch (CoreException e) {
// Do nothing
}
}

private List<MemberInfo> getMemberInfos(ICompilationUnit unit) {
List<MemberInfo> members = new ArrayList<>();
try {
IType[] types = unit.getAllTypes();
for (IType type : types) {
for (IJavaElement child : type.getChildren()) {
if (child instanceof IMember member && Modifier.isPublic(member.getFlags())) {
members.add(new MemberInfo(member.getElementName(), member.getNameRange()));
}
}
}
} catch (JavaModelException e) {
// do nothing
}
return members;
}

public void cleanRenameReferenceCache(ICompilationUnit unit) {
if (unit == null) {
return;
}
IResource resource = unit.getResource();
if (resource == null) {
return;
}
String uri = resource.getLocationURI().toString();
this.documentMemberInfos.remove(uri);
this.documentMarkers.remove(uri);
try {
unit.getResource().deleteMarkers(RENAME_REFERENCE_MARKER_ID, false, IResource.DEPTH_ONE);
} catch (CoreException e) {
// do nothing
}
}

public ICompilationUnit handleClosed(DidCloseTextDocumentParams params) {
String uri = params.getTextDocument().getUri();
ICompilationUnit unit = JDTUtils.resolveCompilationUnit(uri);
Expand Down Expand Up @@ -743,4 +848,22 @@ public void checkChanged() {

}

private static class MemberInfo {
private String name;
private ISourceRange nameRange;

public MemberInfo(String name, ISourceRange nameRange) {
this.name = name;
this.nameRange = nameRange;
}

public String getName() {
return name;
}

public ISourceRange getNameRange() {
return nameRange;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public class CodeActionHandler {
private NonProjectFixProcessor nonProjectFixProcessor;

private PreferenceManager preferenceManager;
private DocumentLifeCycleHandler documentLifeCycleHandler;

public CodeActionHandler(PreferenceManager preferenceManager) {
this.preferenceManager = preferenceManager;
Expand All @@ -91,6 +92,11 @@ public CodeActionHandler(PreferenceManager preferenceManager) {
this.nonProjectFixProcessor = new NonProjectFixProcessor(preferenceManager);
}

public CodeActionHandler(PreferenceManager preferenceManager, DocumentLifeCycleHandler documentLifeCycleHandler) {
this(preferenceManager);
this.documentLifeCycleHandler = documentLifeCycleHandler;
}

public List<Either<Command, CodeAction>> getCodeActionCommands(CodeActionParams params, IProgressMonitor monitor) {
if (monitor.isCanceled()) {
return Collections.emptyList();
Expand Down Expand Up @@ -159,7 +165,7 @@ public List<Either<Command, CodeAction>> getCodeActionCommands(CodeActionParams
if (containsKind(codeActionKinds, CodeActionKind.QuickFix)) {
try {
codeActions.addAll(nonProjectFixProcessor.getCorrections(params, context, locations));
List<ChangeCorrectionProposal> quickfixProposals = this.quickFixProcessor.getCorrections(params, context, locations);
List<ChangeCorrectionProposal> quickfixProposals = this.quickFixProcessor.getCorrections(params, context, locations, documentLifeCycleHandler);
this.quickFixProcessor.addAddAllMissingImportsProposal(context, quickfixProposals);
Set<ChangeCorrectionProposal> quickSet = new TreeSet<>(comparator);
quickSet.addAll(quickfixProposals);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,7 @@ public CompletableFuture<List<Either<SymbolInformation, DocumentSymbol>>> docume
@Override
public CompletableFuture<List<Either<Command, CodeAction>>> codeAction(CodeActionParams params) {
logInfo(">> document/codeAction");
CodeActionHandler handler = new CodeActionHandler(this.preferenceManager);
CodeActionHandler handler = new CodeActionHandler(this.preferenceManager, this.documentLifeCycleHandler);
return computeAsync((monitor) -> {
waitForLifecycleJobs(monitor);
return handler.getCodeActionCommands(params, monitor);
Expand Down Expand Up @@ -813,7 +813,7 @@ public CompletableFuture<Either3<Range, PrepareRenameResult, PrepareRenameDefaul
@Override
public CompletableFuture<WorkspaceEdit> rename(RenameParams params) {
logInfo(">> document/rename");
RenameHandler handler = new RenameHandler(preferenceManager);
RenameHandler handler = new RenameHandler(preferenceManager, this.documentLifeCycleHandler);
return computeAsync((monitor) -> {
waitForLifecycleJobs(monitor);
return handler.rename(params, monitor);
Expand Down
Loading