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

Add missing import on paste #2320

Merged
merged 2 commits into from
Jan 11, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
add missing imports on paste
Signed-off-by: Shi Chen <chenshi@microsoft.com>
  • Loading branch information
CsCherrYY committed Jan 6, 2023
commit b4a259517ea93316fe1eb632734f2a1683c65b34
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ public static String[] getStaticImportFavorites(ICompilationUnit cu, final Strin
dummyCU.append("\n}\n }"); //$NON-NLS-1$

ICompilationUnit newCU= null;
String contents = cu.getBuffer().getContents();
try {
newCU= cu.getWorkingCopy(null);
newCU.getBuffer().setContents(dummyCU.toString());
Expand Down Expand Up @@ -297,10 +298,13 @@ public void accept(CompletionProposal proposal) {
requestor.setFavoriteReferences(favorites);

newCU.codeComplete(offset, requestor);

// if cu is working copy, we should restore the contents saved previously.
if (cu.isWorkingCopy()) {
cu.getBuffer().setContents(contents);
}
return result.toArray(new String[result.size()]);
} finally {
if (newCU != null) {
if (newCU != null && !cu.isWorkingCopy()) {
newCU.discardWorkingCopy();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,42 @@
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal.handlers;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringEscapeUtils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.internal.corext.refactoring.rename.RenameAnalyzeUtil;
import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.handlers.OrganizeImportsHandler.ImportCandidate;
import org.eclipse.jdt.ls.core.internal.handlers.OrganizeImportsHandler.ImportSelection;
import org.eclipse.jdt.ls.core.internal.text.correction.SourceAssistProcessor;
import org.eclipse.lsp4j.FormattingOptions;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.WorkspaceEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;

/**
* Handles paste events, modifying the pasted value and supplying additional
Expand Down Expand Up @@ -179,7 +196,15 @@ public static DocumentPasteEdit handlePasteEvent(PasteEventParams params, IProgr
parser.setSource(cu);
parser.setResolveBindings(false);
CompilationUnit ast = (CompilationUnit) parser.createAST(monitor);
return handleStringPasteEvent(params, cu, ast, monitor);
DocumentPasteEdit edit = handleStringPasteEvent(params, cu, ast, monitor);
if (edit == null) {
try {
edit = getMissingImportsWorkspaceEdit(params, cu, monitor);
} catch (CoreException e) {
// Do nothing
}
}
return edit;
}

private static DocumentPasteEdit handleStringPasteEvent(PasteEventParams params, ICompilationUnit cu, CompilationUnit ast, IProgressMonitor monitor) {
Expand Down Expand Up @@ -225,6 +250,51 @@ private static DocumentPasteEdit handleStringPasteEvent(PasteEventParams params,

}

public static DocumentPasteEdit getMissingImportsWorkspaceEdit(PasteEventParams params, ICompilationUnit cu, IProgressMonitor monitor) throws CoreException {
Range range = params.getLocation().getRange();
String originalDocumentUri = params.getCopiedDocumentUri();
String insertText = params.getText();
int offset = JsonRpcHelpers.toOffset(cu, range.getStart().getLine(), range.getStart().getCharacter());
int length = JsonRpcHelpers.toOffset(cu, range.getEnd().getLine(), range.getEnd().getCharacter()) - offset;
Function<ImportSelection[], ImportCandidate[]> chooseFunc = null;
ICompilationUnit tempUnit = RenameAnalyzeUtil.createNewWorkingCopy(cu, new TextChangeManager(true), new WorkingCopyOwner() {
}, new SubProgressMonitor(monitor == null ? new NullProgressMonitor() : monitor, 1));
tempUnit.applyTextEdit(new ReplaceEdit(offset, length, insertText), monitor);
if (originalDocumentUri != null) {
ICompilationUnit tempOriginalUnit = JDTUtils.resolveCompilationUnit(originalDocumentUri);
if (tempOriginalUnit == null) {
IClassFile classFile = JDTUtils.resolveClassFile(originalDocumentUri);
if (classFile != null) {
tempOriginalUnit = classFile.getWorkingCopy(new WorkingCopyOwner() {
}, monitor);
}
}
if (tempOriginalUnit != null) {
Set<String> names = Arrays.stream(tempOriginalUnit.getImports()).map(importDecl -> importDecl.getElementName()).filter(name -> name != null).collect(Collectors.toSet());
chooseFunc = (selections) -> {
List<ImportCandidate> candidates = new ArrayList<>();
for (ImportSelection selection : selections) {
for (ImportCandidate candidate : selection.candidates) {
if (names.contains(candidate.fullyQualifiedName)) {
candidates.add(candidate);
break;
}
}
}
return candidates.toArray(new ImportCandidate[] {});
};
}
tempOriginalUnit.discardWorkingCopy();
}
TextEdit edit = OrganizeImportsHandler.organizeImports(tempUnit, chooseFunc, true, monitor);
if (edit == null) {
return null;
}
WorkspaceEdit workspaceEdit = SourceAssistProcessor.convertToWorkspaceEdit(tempUnit, edit);
tempUnit.discardWorkingCopy();
return new DocumentPasteEdit(insertText, workspaceEdit);
}

private static String getEol(String text) {
return text.contains("\r\n") ? "\r\n" : "\n";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal.handlers;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.util.List;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IPackageFragment;
Expand All @@ -23,6 +28,8 @@
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextEdit;
import org.eclipse.lsp4j.WorkspaceEdit;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
Expand Down Expand Up @@ -209,4 +216,113 @@ private static Location l(String uri, int startLine, int startChar, int endLine,
return location;
}

@Test
public void testGetAddImportsWorkspaceEdit() throws CoreException {
//@formatter:off
ICompilationUnit unit = fPackageP.createCompilationUnit("B.java", "package p;\r\n" +
"\r\n" +
"public class B {\r\n" +
"}"
, true, null);
String content = " public List<String> b;\r\n" +
" public Set<String> c;\r\n";
//@formatter:on
String uri = JDTUtils.toURI(unit);
Range range = new Range(new Position(3, 0), new Position(3, 0));
PasteEventParams params = new PasteEventParams(new Location(uri, range), content, null, new FormattingOptions(4, false));
DocumentPasteEdit documentPasteEdit = PasteEventHandler.getMissingImportsWorkspaceEdit(params, unit, monitor);
assertNotNull(documentPasteEdit);
WorkspaceEdit edit = documentPasteEdit.getAdditionalEdit();
List<TextEdit> changes = edit.getChanges().get(uri);
assertNotNull(changes);
assertEquals(1, changes.size());
//@formatter:off
String expect = "\r\n" +
"\r\n" +
"import java.util.List;\r\n" +
"import java.util.Set;\r\n" +
"\r\n";
//@formatter:on
assertEquals(expect, changes.get(0).getNewText());
assertEquals(new Range(new Position(0, 10), new Position(2, 0)), changes.get(0).getRange());
}

@Test
public void testGetAddImportsAmbigousWorkspaceEdit() throws CoreException {
//@formatter:off
ICompilationUnit unit = fPackageP.createCompilationUnit("B.java", "package p;\r\n" +
"\r\n" +
"public class B {\r\n" +
"}"
, true, null);
ICompilationUnit unit1 = fPackageTest.createCompilationUnit("List.java", "package test;\r\n" +
"\r\n" +
"public class List {\r\n" +
"}"
, true, null);
String content = " public List<String> b;\r\n" +
" public Set<String> c;\r\n";
//@formatter:on
String uri = JDTUtils.toURI(unit);
Range range = new Range(new Position(3, 0), new Position(3, 0));
PasteEventParams params = new PasteEventParams(new Location(uri, range), content, null, new FormattingOptions(4, false));
DocumentPasteEdit documentPasteEdit = PasteEventHandler.getMissingImportsWorkspaceEdit(params, unit, monitor);
assertNotNull(documentPasteEdit);
WorkspaceEdit edit = documentPasteEdit.getAdditionalEdit();
List<TextEdit> changes = edit.getChanges().get(uri);
assertNotNull(changes);
assertEquals(1, changes.size());
//@formatter:off
String expect = "\r\n" +
"\r\n" +
"import java.util.Set;\r\n" +
"\r\n";
//@formatter:on
assertEquals(expect, changes.get(0).getNewText());
assertEquals(new Range(new Position(0, 10), new Position(2, 0)), changes.get(0).getRange());
}

@Test
public void testGetAddImportsResolveAmbigousWorkspaceEdit() throws CoreException {
//@formatter:off
ICompilationUnit unit = fPackageP.createCompilationUnit("B.java", "package p;\r\n" +
"\r\n" +
"public class B {\r\n" +
"}"
, true, null);
ICompilationUnit unit1 = fPackageTest.createCompilationUnit("List.java", "package test;\r\n" +
"\r\n" +
"public class List {\r\n" +
"}"
, true, null);
ICompilationUnit unit2 = fPackageP.createCompilationUnit("C.java", "package p;\r\n" +
"\r\n" +
"import java.util.List;\r\n" +
"import java.util.Set;\r\n" +
"public class C {\r\n" +
" public List<String> b;\r\n" +
" public Set<String> c;\r\n" +
"}"
, true, null);
String content = " public List<String> b;\r\n" +
" public Set<String> c;\r\n";
//@formatter:on
String uri = JDTUtils.toURI(unit);
Range range = new Range(new Position(3, 0), new Position(3, 0));
PasteEventParams params = new PasteEventParams(new Location(uri, range), content, JDTUtils.toURI(unit2), new FormattingOptions(4, false));
DocumentPasteEdit documentPasteEdit = PasteEventHandler.getMissingImportsWorkspaceEdit(params, unit, monitor);
assertNotNull(documentPasteEdit);
WorkspaceEdit edit = documentPasteEdit.getAdditionalEdit();
List<TextEdit> changes = edit.getChanges().get(uri);
assertNotNull(changes);
assertEquals(1, changes.size());
String expect = "\r\n" +
"\r\n" +
"import java.util.List;\r\n" +
"import java.util.Set;\r\n" +
"\r\n";
assertEquals(expect, changes.get(0).getNewText());
assertEquals(new Range(new Position(0, 10), new Position(2, 0)), changes.get(0).getRange());
}

}