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

Support refactoring package name #1414

Merged
merged 2 commits into from
Apr 29, 2020
Merged
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 @@ -164,8 +164,9 @@ private static void convertMoveCompilationUnitChange(WorkspaceEdit edit, MoveCom
String oldPackageName = packDecls.length > 0 ? packDecls[0].getElementName() : "";
if (!Objects.equals(oldPackageName, newPackage.getElementName())) {
// update the package declaration
updatePackageStatement(astCU, newPackage.getElementName(), rewrite, unit);
convertTextEdit(edit, unit, rewrite.rewriteAST());
if (updatePackageStatement(astCU, newPackage.getElementName(), rewrite, unit)) {
convertTextEdit(edit, unit, rewrite.rewriteAST());
}
}

RenameFile cuResourceChange = new RenameFile();
Expand All @@ -188,41 +189,32 @@ private static void convertCreateCompilationUnitChange(WorkspaceEdit edit, Creat

private static void convertRenamePackcageChange(WorkspaceEdit edit, RenamePackageChange packageChange) throws CoreException {
IPackageFragment pack = (IPackageFragment) packageChange.getModifiedElement();
List<ICompilationUnit> units = new ArrayList<>();
IPath newPackageFragment = new Path(packageChange.getNewName().replace('.', IPath.SEPARATOR));
IPath oldPackageFragment = new Path(packageChange.getOldName().replace('.', IPath.SEPARATOR));
IPath newPackagePath = pack.getResource().getLocation().removeLastSegments(oldPackageFragment.segmentCount()).append(newPackageFragment);
if (packageChange.getRenameSubpackages()) {
IPackageFragment[] allPackages = JavaElementUtil.getPackageAndSubpackages(pack);
String oldPrefix = packageChange.getOldName();
for (IPackageFragment currentPackage : allPackages) {
units.addAll(Arrays.asList(currentPackage.getCompilationUnits()));
String newPkgName = packageChange.getNewName() + currentPackage.getElementName().substring(oldPrefix.length());
//update package's declaration
convertPackageUpdateEdit(currentPackage.getCompilationUnits(), newPkgName, edit);
}
} else {
units.addAll(Arrays.asList(pack.getCompilationUnits()));
}

//update package's declaration
for (ICompilationUnit cu : units) {
CompilationUnit unit = new RefactoringASTParser(IASTSharedValues.SHARED_AST_LEVEL).parse(cu, true);
ASTRewrite rewrite = ASTRewrite.create(unit.getAST());
updatePackageStatement(unit, packageChange.getNewName(), rewrite, cu);
TextEdit textEdit = rewrite.rewriteAST();
convertTextEdit(edit, cu, textEdit);
}

IPath newPackageFragment = new Path(packageChange.getNewName().replace('.', IPath.SEPARATOR));
IPath oldPackageFragment = new Path(packageChange.getOldName().replace('.', IPath.SEPARATOR));
IPath newPackagePath = pack.getResource().getLocation().removeLastSegments(oldPackageFragment.segmentCount()).append(newPackageFragment);

if (packageChange.getRenameSubpackages()) {
RenameFile renameFile = new RenameFile();
renameFile.setNewUri(ResourceUtils.fixURI(newPackagePath.toFile().toURI()));
renameFile.setOldUri(ResourceUtils.fixURI(pack.getResource().getRawLocationURI()));
edit.getDocumentChanges().add(Either.forRight(renameFile));
} else {
//update package's declaration
convertPackageUpdateEdit(pack.getCompilationUnits(), packageChange.getNewName(), edit);

CreateFile createFile = new CreateFile();
createFile.setUri(ResourceUtils.fixURI(newPackagePath.append(TEMP_FILE_NAME).toFile().toURI()));
createFile.setOptions(new CreateFileOptions(false, true));
edit.getDocumentChanges().add(Either.forRight(createFile));

for (ICompilationUnit unit : units) {
for (ICompilationUnit unit : pack.getCompilationUnits()) {
RenameFile cuResourceChange = new RenameFile();
cuResourceChange.setOldUri(ResourceUtils.fixURI(unit.getResource().getLocationURI()));
IPath newCUPath = newPackagePath.append(unit.getPath().lastSegment());
Expand Down Expand Up @@ -315,32 +307,54 @@ private static boolean isPrimaryType(IType type) {
return type.getDeclaringType() == null && JavaCore.removeJavaLikeExtension(cuName).equals(typeName);
}

private static void updatePackageStatement(CompilationUnit astCU, String pkgName, ASTRewrite rewriter, ICompilationUnit cu) throws JavaModelException {
private static void convertPackageUpdateEdit(ICompilationUnit[] cus, String newPkgName, WorkspaceEdit rootEdit) throws JavaModelException {
for (ICompilationUnit cu : cus) {
convertPackageUpdateEdit(cu, newPkgName, rootEdit);
}
}

private static void convertPackageUpdateEdit(ICompilationUnit cu, String newPkgName, WorkspaceEdit rootEdit) throws JavaModelException {
CompilationUnit unit = new RefactoringASTParser(IASTSharedValues.SHARED_AST_LEVEL).parse(cu, true);
ASTRewrite rewrite = ASTRewrite.create(unit.getAST());
if (updatePackageStatement(unit, newPkgName, rewrite, cu)) {
TextEdit textEdit = rewrite.rewriteAST();
convertTextEdit(rootEdit, cu, textEdit);
}
}

private static boolean updatePackageStatement(CompilationUnit astCU, String pkgName, ASTRewrite rewriter, ICompilationUnit cu) throws JavaModelException {
boolean defaultPackage = pkgName.isEmpty();
AST ast = astCU.getAST();
if (defaultPackage) {
// remove existing package statement
PackageDeclaration pkg = astCU.getPackage();
if (pkg != null) {
int pkgStart;
Javadoc javadoc = pkg.getJavadoc();
if (javadoc != null) {
pkgStart = javadoc.getStartPosition() + javadoc.getLength() + 1;
} else {
pkgStart = pkg.getStartPosition();
}
int extendedStart = astCU.getExtendedStartPosition(pkg);
if (pkgStart != extendedStart) {
String commentSource = cu.getSource().substring(extendedStart, pkgStart);
ASTNode comment = rewriter.createStringPlaceholder(commentSource, ASTNode.PACKAGE_DECLARATION);
rewriter.set(astCU, CompilationUnit.PACKAGE_PROPERTY, comment, null);
} else {
rewriter.set(astCU, CompilationUnit.PACKAGE_PROPERTY, null, null);
}
if (pkg == null) {
return false;
}

int pkgStart;
Javadoc javadoc = pkg.getJavadoc();
if (javadoc != null) {
pkgStart = javadoc.getStartPosition() + javadoc.getLength() + 1;
} else {
pkgStart = pkg.getStartPosition();
}
int extendedStart = astCU.getExtendedStartPosition(pkg);
if (pkgStart != extendedStart) {
String commentSource = cu.getSource().substring(extendedStart, pkgStart);
ASTNode comment = rewriter.createStringPlaceholder(commentSource, ASTNode.PACKAGE_DECLARATION);
rewriter.set(astCU, CompilationUnit.PACKAGE_PROPERTY, comment, null);
} else {
rewriter.set(astCU, CompilationUnit.PACKAGE_PROPERTY, null, null);
}
} else {
org.eclipse.jdt.core.dom.PackageDeclaration pkg = astCU.getPackage();
if (pkg != null) {
// Skip if the new package name is same as the existing package name.
if (Objects.equals(pkg.getName().getFullyQualifiedName(), pkgName)) {
return false;
}

// rename package statement
Name name = ast.newName(pkgName);
rewriter.set(pkg, PackageDeclaration.NAME_PROPERTY, name, null);
Expand All @@ -351,6 +365,8 @@ private static void updatePackageStatement(CompilationUnit astCU, String pkgName
rewriter.set(astCU, CompilationUnit.PACKAGE_PROPERTY, pkg, null);
}
}

return true;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,11 @@ public static Result listSourcePaths() {
IPath relativePath = entryPath.makeRelativeTo(projectRoot.getFullPath());
IPath location = projectRoot.getRawLocation().append(relativePath);
IPath displayPath = getWorkspacePath(location);
sourcePathList.add(new SourcePath(location != null ? location.toOSString() : "", displayPath != null ? displayPath.toOSString() : entryPath.toOSString(), projectName, projectType));
sourcePathList.add(new SourcePath(location != null ? location.toOSString() : "",
displayPath != null ? displayPath.toOSString() : entryPath.toOSString(),
entryPath.toOSString(),
projectName,
projectType));
}
} catch (JavaModelException e) {
JavaLanguageServerPlugin.logException("Failed to resolve the existing source paths in current workspace.", e);
Expand Down Expand Up @@ -238,12 +242,14 @@ public static class ListCommandResult extends Result {
public static class SourcePath {
public String path;
public String displayPath;
public String classpathEntry;
public String projectName;
public String projectType;

SourcePath(String path, String displayPath, String projectName, String projectType) {
SourcePath(String path, String displayPath, String classpathEntry, String projectName, String projectType) {
this.path = path;
this.displayPath = displayPath;
this.classpathEntry = classpathEntry;
this.projectName = projectName;
this.projectType = projectType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.stream.Stream;
import java.util.Set;

import org.eclipse.core.resources.IContainer;
Expand Down Expand Up @@ -862,6 +863,7 @@ private RefactoringStatus analyzeAffectedCompilationUnits() throws CoreException
//TODO: also for both fReferencesTo...; only check each CU once!
RefactoringStatus result= new RefactoringStatus();
fOccurrences= Checks.excludeCompilationUnits(fOccurrences, result);
fOccurrences= excludeInvalidResult(fOccurrences);
if (result.hasFatalError()) {
return result;
}
Expand All @@ -870,6 +872,11 @@ private RefactoringStatus analyzeAffectedCompilationUnits() throws CoreException
return result;
}

private SearchResultGroup[] excludeInvalidResult(SearchResultGroup[] grouped) {
return Stream.of(grouped).filter(group -> group.getResource() != null && group.getResource().exists())
.toArray(SearchResultGroup[]::new);
}

/**
* @return search scope with
* <p>- fPackage and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

package org.eclipse.jdt.ls.core.internal.handlers;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

Expand All @@ -23,22 +24,31 @@
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.ls.core.internal.ChangeUtil;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
import org.eclipse.jdt.ls.core.internal.ResourceUtils;
import org.eclipse.jdt.ls.core.internal.commands.BuildPathCommand;
import org.eclipse.jdt.ls.core.internal.commands.BuildPathCommand.ListCommandResult;
import org.eclipse.jdt.ls.core.internal.commands.BuildPathCommand.SourcePath;
import org.eclipse.jdt.ls.core.internal.corext.refactoring.rename.RenamePackageProcessor;
import org.eclipse.jdt.ls.core.internal.corext.refactoring.rename.RenameSupport;
import org.eclipse.lsp4j.WorkspaceEdit;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CheckConditionsOperation;
import org.eclipse.ltk.core.refactoring.CreateChangeOperation;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.RefactoringTickProvider;
import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring;
import org.eclipse.ltk.internal.core.refactoring.NotCancelableProgressMonitor;

public class FileEventHandler {

Expand Down Expand Up @@ -75,7 +85,7 @@ public void run(IProgressMonitor monitor) throws CoreException {
}
unit = units[0];
}

if (unit != null) {
String oldPrimaryType = getPrimaryTypeName(oldUri);
String newPrimaryType = getPrimaryTypeName(newUri);
Expand All @@ -95,14 +105,101 @@ public void run(IProgressMonitor monitor) throws CoreException {
return root;
}

public static WorkspaceEdit handleWillRenameFiles(FileRenameParams params, IProgressMonitor monitor) {
if (params.files == null || params.files.isEmpty()) {
return null;
}

FileRenameEvent[] renamefolders = params.files.stream().filter(event -> isFolderRenameEvent(event)).toArray(FileRenameEvent[]::new);
if (renamefolders.length == 0) {
return null;
}

SourcePath[] sourcePaths = getSourcePaths();
if (sourcePaths == null || sourcePaths.length == 0) {
return null;
}

return computePackageRenameEdit(renamefolders, sourcePaths, monitor);
}

private static WorkspaceEdit computePackageRenameEdit(FileRenameEvent[] renameEvents, SourcePath[] sourcePaths, IProgressMonitor monitor) {
WorkspaceEdit[] root = new WorkspaceEdit[1];
SubMonitor submonitor = SubMonitor.convert(monitor, "Computing package rename updates...", 100 * renameEvents.length);
for (FileRenameEvent event : renameEvents) {
IPath oldLocation = ResourceUtils.filePathFromURI(event.oldUri);
IPath newLocation = ResourceUtils.filePathFromURI(event.newUri);
for (SourcePath sourcePath : sourcePaths) {
IPath sourceLocation = Path.fromOSString(sourcePath.path);
IPath sourceEntry = Path.fromOSString(sourcePath.classpathEntry);
if (sourceLocation.isPrefixOf(oldLocation)) {
SubMonitor renameMonitor = submonitor.split(100);
try {
IJavaProject javaProject = ProjectUtils.getJavaProject(sourcePath.projectName);
if (javaProject == null) {
break;
}

IPackageFragmentRoot packageRoot = javaProject.findPackageFragmentRoot(sourceEntry);
if (packageRoot == null) {
break;
}

String oldPackageName = String.join(".", oldLocation.makeRelativeTo(sourceLocation).segments());
String newPackageName = String.join(".", newLocation.makeRelativeTo(sourceLocation).segments());
IPackageFragment oldPackageFragment = packageRoot.getPackageFragment(oldPackageName);
if (oldPackageFragment != null && !oldPackageFragment.isDefaultPackage() && oldPackageFragment.getResource() != null) {
oldPackageFragment.getResource().refreshLocal(IResource.DEPTH_INFINITE, null);
if (oldPackageFragment.exists()) {
ResourcesPlugin.getWorkspace().run((pm) -> {
WorkspaceEdit edit = getRenameEdit(oldPackageFragment, newPackageName, pm);
root[0] = ChangeUtil.mergeChanges(root[0], edit, true);
}, oldPackageFragment.getSchedulingRule(), IResource.NONE, renameMonitor);
}
}
} catch (CoreException e) {
JavaLanguageServerPlugin.logException("Failed to compute the package rename update", e);
} finally {
renameMonitor.done();
}

break;
}
}
}

submonitor.done();
return ChangeUtil.hasChanges(root[0]) ? root[0] : null;
}

private static SourcePath[] getSourcePaths() {
SourcePath[] sourcePaths = new SourcePath[0];
ListCommandResult result = (ListCommandResult) BuildPathCommand.listSourcePaths();
if (result.status && result.data != null && result.data.length > 0) {
sourcePaths = result.data;
}

Arrays.sort(sourcePaths, (a, b) -> {
return b.path.length() - a.path.length();
});

return sourcePaths;
}

private static boolean isFileNameRenameEvent(FileRenameEvent event) {
IPath oldPath = ResourceUtils.filePathFromURI(event.oldUri);
IPath newPath = ResourceUtils.filePathFromURI(event.newUri);
return oldPath.lastSegment().endsWith(".java")
return newPath.toFile().isFile() && oldPath.lastSegment().endsWith(".java")
&& newPath.lastSegment().endsWith(".java")
&& Objects.equals(oldPath.removeLastSegments(1), newPath.removeLastSegments(1));
}

private static boolean isFolderRenameEvent(FileRenameEvent event) {
IPath oldPath = ResourceUtils.filePathFromURI(event.oldUri);
IPath newPath = ResourceUtils.filePathFromURI(event.newUri);
return (oldPath.toFile().isDirectory() || newPath.toFile().isDirectory()) && Objects.equals(oldPath.removeLastSegments(1), newPath.removeLastSegments(1));
}

private static String getPrimaryTypeName(String uri) {
String fileName = ResourceUtils.filePathFromURI(uri).lastSegment();
int idx = fileName.lastIndexOf(".");
Expand Down Expand Up @@ -137,16 +234,21 @@ private static WorkspaceEdit getRenameEdit(IJavaElement targetElement, String ne
return null;
}

RenameRefactoring renameRefactoring = renameSupport.getRenameRefactoring();
if (targetElement instanceof IPackageFragment) {
((RenamePackageProcessor) renameSupport.getJavaRenameProcessor()).setRenameSubpackages(true);
}

CheckConditionsOperation check = new CheckConditionsOperation(renameRefactoring, CheckConditionsOperation.ALL_CONDITIONS);
CreateChangeOperation create = new CreateChangeOperation(check, RefactoringStatus.FATAL);
create.run(monitor);
if (check.getStatus().getSeverity() >= RefactoringStatus.FATAL) {
JavaLanguageServerPlugin.logError(check.getStatus().getMessageMatchingSeverity(RefactoringStatus.ERROR));
RenameRefactoring renameRefactoring = renameSupport.getRenameRefactoring();
RefactoringTickProvider rtp = renameRefactoring.getRefactoringTickProvider();
SubMonitor submonitor = SubMonitor.convert(monitor, "Creating rename changes...", rtp.getAllTicks());
CheckConditionsOperation checkConditionOperation = new CheckConditionsOperation(renameRefactoring, CheckConditionsOperation.ALL_CONDITIONS);
checkConditionOperation.run(submonitor.split(rtp.getCheckAllConditionsTicks()));
if (checkConditionOperation.getStatus().getSeverity() >= RefactoringStatus.FATAL) {
JavaLanguageServerPlugin.logError(checkConditionOperation.getStatus().getMessageMatchingSeverity(RefactoringStatus.ERROR));
}

Change change = create.getChange();
Change change = renameRefactoring.createChange(submonitor.split(rtp.getCreateChangeTicks()));
change.initializeValidationData(new NotCancelableProgressMonitor(submonitor.split(rtp.getInitializeChangeTicks())));
return ChangeUtil.convertToWorkspaceEdit(change);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,14 @@ public CompletableFuture<WorkspaceEdit> didRenameFiles(FileRenameParams params)
});
}

@Override
public CompletableFuture<WorkspaceEdit> willRenameFiles(FileRenameParams params) {
logInfo(">> document/willRenameFiles");
return computeAsyncWithClientProgress((monitor) -> {
return FileEventHandler.handleWillRenameFiles(params, monitor);
});
}

/* (non-Javadoc)
* @see org.eclipse.jdt.ls.core.internal.JavaProtocolExtensions#ClassFileContents(org.eclipse.lsp4j.TextDocumentIdentifier)
*/
Expand Down
Loading