From 1e879849d6947afef5dcdafaa074bbfb6c5bff66 Mon Sep 17 00:00:00 2001 From: Roland Grunberg Date: Tue, 22 Nov 2022 23:34:49 -0500 Subject: [PATCH] Create cleanup actions for some existing quick assists. - Add final modifier where possible - Convert switch statement to switch expression - Use pattern matching for instanceof checks - Convert anonymous function to lambda expression - Add test cases, and set CleanUpsTest compliance to 19 - Due to LSP limitations (no overlapping text edits), we now return the final state of the document after all cleanups are applied as a text edit Signed-off-by: Roland Grunberg --- .../internal/cleanup/CleanUpRegistry.java | 31 ++- .../core/internal/cleanup/CleanUpUtils.java | 23 +- .../cleanup/InstanceofPatternMatch.java | 57 +++++ .../cleanup/LambdaExpressionCleanup.java | 54 ++++ .../cleanup/SwitchExpressionCleanup.java | 57 +++++ .../VariableDeclarationFixCleanup.java | 57 +++++ .../core/internal/cleanup/CleanUpsTest.java | 233 ++++++++++++++++++ 7 files changed, 496 insertions(+), 16 deletions(-) create mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/InstanceofPatternMatch.java create mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/LambdaExpressionCleanup.java create mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/SwitchExpressionCleanup.java create mode 100644 org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/VariableDeclarationFixCleanup.java diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/CleanUpRegistry.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/CleanUpRegistry.java index a7061693b6..3040dae91a 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/CleanUpRegistry.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/CleanUpRegistry.java @@ -19,8 +19,11 @@ import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.IBuffer; +import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.manipulation.CleanUpContextCore; import org.eclipse.jdt.ls.core.internal.JDTUtils; import org.eclipse.lsp4j.TextDocumentIdentifier; @@ -42,6 +45,10 @@ public CleanUpRegistry() { cleanUpsList.add(new AddDeprecatedAnnotationCleanUp()); cleanUpsList.add(new StringConcatToTextBlockCleanUp()); cleanUpsList.add(new InvertEqualsCleanUp()); + cleanUpsList.add(new VariableDeclarationFixCleanup()); + cleanUpsList.add(new SwitchExpressionCleanup()); + cleanUpsList.add(new InstanceofPatternMatch()); + cleanUpsList.add(new LambdaExpressionCleanup()); // Store in a Map so that they can be accessed by ID quickly cleanUps = new HashMap<>(); @@ -94,10 +101,28 @@ public List getEditsForAllActiveCleanUps(TextDocumentIdentifier textDo // build the context after setting the compiler options so that the built AST has all the required markers CleanUpContextCore context = CleanUpUtils.getCleanUpContext(textDocumentId, opts, monitor); - List textEdits = new ArrayList<>(); - for (ISimpleCleanUp cleanUp : cleanUpsToRun) { - textEdits.addAll(CleanUpUtils.getTextEditFromCleanUp(cleanUp, context, monitor)); + ICompilationUnit cu = context.getCompilationUnit(); + + try { + ICompilationUnit wc = cu.getWorkingCopy(monitor); + for (ISimpleCleanUp cleanUp : cleanUpsToRun) { + org.eclipse.text.edits.TextEdit jdtEdit = CleanUpUtils.getTextEditFromCleanUp(cleanUp, context, monitor); + if (jdtEdit != null) { + wc.applyTextEdit(jdtEdit, monitor); + context = CleanUpUtils.getCleanUpContext(wc, opts, monitor); + } + } + // https://microsoft.github.io/language-server-protocol/specifications/specification-3-16/#textEditArray + // Cleanups may have overlapping text edits but LSP does not support this + // Generate text edit as the entire document + IBuffer wcBuff = wc.getBuffer(); + String newText = wcBuff.getContents(); + TextEdit te = new TextEdit(JDTUtils.toRange(cu, 0, cu.getBuffer().getLength()), newText); + textEdits.add(te); + + } catch (JavaModelException e) { + // continue } return textEdits; diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/CleanUpUtils.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/CleanUpUtils.java index 65ca5b187a..56aebeb4bb 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/CleanUpUtils.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/CleanUpUtils.java @@ -12,8 +12,6 @@ *******************************************************************************/ package org.eclipse.jdt.ls.core.internal.cleanup; -import java.util.Collections; -import java.util.List; import java.util.Map; import org.eclipse.core.runtime.CoreException; @@ -27,9 +25,8 @@ import org.eclipse.jdt.internal.corext.dom.IASTSharedValues; import org.eclipse.jdt.ls.core.internal.JDTUtils; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; -import org.eclipse.jdt.ls.core.internal.TextEditConverter; import org.eclipse.lsp4j.TextDocumentIdentifier; -import org.eclipse.lsp4j.TextEdit; +import org.eclipse.text.edits.TextEdit; /** * Functions for working with JDT ICleanUpCore and ISimpleCleanUp. @@ -53,6 +50,11 @@ public static CleanUpContextCore getCleanUpContext(TextDocumentIdentifier textDo return new CleanUpContextCore(unit, ast); } + public static CleanUpContextCore getCleanUpContext(ICompilationUnit unit, Map compilerOpts, IProgressMonitor monitor) { + CompilationUnit ast = createASTWithOpts(unit, compilerOpts, monitor); + return new CleanUpContextCore(unit, ast); + } + /** * Returns a non-null list of text edits for the given clean up. * @@ -64,25 +66,20 @@ public static CleanUpContextCore getCleanUpContext(TextDocumentIdentifier textDo * the progress monitor * @return a non-null list of text edits for the given clean up */ - public static List getTextEditFromCleanUp(ISimpleCleanUp cleanUp, CleanUpContextCore context, IProgressMonitor monitor) { + public static TextEdit getTextEditFromCleanUp(ISimpleCleanUp cleanUp, CleanUpContextCore context, IProgressMonitor monitor) { try { ICleanUpFixCore fix = cleanUp != null ? cleanUp.createFix(context) : null; if (fix == null) { - return Collections.emptyList(); + return null; } CompilationUnitChange cleanUpChange = fix.createChange(monitor); org.eclipse.text.edits.TextEdit jdtEdit = cleanUpChange.getEdit(); - if (jdtEdit == null) { - return Collections.emptyList(); - } - TextEditConverter converter = new TextEditConverter(context.getCompilationUnit(), jdtEdit); - List lspEdit = converter.convert(); - return lspEdit != null ? lspEdit : Collections.emptyList(); + return jdtEdit; } catch (CoreException e) { JavaLanguageServerPlugin.logError(String.format("Failed to create text edit for clean up %s", cleanUp.getIdentifier())); } - return Collections.emptyList(); + return null; } private static CompilationUnit createASTWithOpts(ICompilationUnit cu, Map opts, IProgressMonitor monitor) { diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/InstanceofPatternMatch.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/InstanceofPatternMatch.java new file mode 100644 index 0000000000..ae794469be --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/InstanceofPatternMatch.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2022 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ls.core.internal.cleanup; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.manipulation.CleanUpContextCore; +import org.eclipse.jdt.core.manipulation.ICleanUpFixCore; +import org.eclipse.jdt.internal.corext.fix.PatternMatchingForInstanceofFixCore; + +/** + * Represents a cleanup that uses pattern matching for 'instanceof' cast checks + */ +public class InstanceofPatternMatch implements ISimpleCleanUp { + + /* (non-Javadoc) + * @see org.eclipse.jdt.ls.core.internal.cleanup.ISimpleCleanUp#getIdentifier() + */ + @Override + public String getIdentifier() { + return "instanceofPatternMatch"; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.ls.core.internal.cleanup.ISimpleCleanUp#createFix(org.eclipse.jdt.core.manipulation.CleanUpContextCore) + */ + @Override + public ICleanUpFixCore createFix(CleanUpContextCore context) throws CoreException { + CompilationUnit unit = context.getAST(); + if (unit == null) { + return null; + } + return PatternMatchingForInstanceofFixCore.createCleanUp(unit); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.ls.core.internal.cleanup.ISimpleCleanUp#getRequiredCompilerMarkers() + */ + @Override + public List getRequiredCompilerMarkers() { + return Collections.emptyList(); + } + +} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/LambdaExpressionCleanup.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/LambdaExpressionCleanup.java new file mode 100644 index 0000000000..8f7b9d3690 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/LambdaExpressionCleanup.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2022 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ls.core.internal.cleanup; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.manipulation.CleanUpContextCore; +import org.eclipse.jdt.core.manipulation.ICleanUpFixCore; +import org.eclipse.jdt.internal.corext.fix.LambdaExpressionsFixCore; + +public class LambdaExpressionCleanup implements ISimpleCleanUp { + + /* (non-Javadoc) + * @see org.eclipse.jdt.ls.core.internal.cleanup.ISimpleCleanUp#getIdentifier() + */ + @Override + public String getIdentifier() { + return "lambdaExpression"; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.ls.core.internal.cleanup.ISimpleCleanUp#createFix(org.eclipse.jdt.core.manipulation.CleanUpContextCore) + */ + @Override + public ICleanUpFixCore createFix(CleanUpContextCore context) throws CoreException { + CompilationUnit unit = context.getAST(); + if (unit == null) { + return null; + } + return LambdaExpressionsFixCore.createCleanUp(unit, true, false); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.ls.core.internal.cleanup.ISimpleCleanUp#getRequiredCompilerMarkers() + */ + @Override + public List getRequiredCompilerMarkers() { + return Collections.emptyList(); + } + +} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/SwitchExpressionCleanup.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/SwitchExpressionCleanup.java new file mode 100644 index 0000000000..4db4c6db44 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/SwitchExpressionCleanup.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2022 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ls.core.internal.cleanup; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.manipulation.CleanUpContextCore; +import org.eclipse.jdt.core.manipulation.ICleanUpFixCore; +import org.eclipse.jdt.internal.corext.fix.SwitchExpressionsFixCore; + +/** + * Represents a cleanup that converts a switch statement to a switch expression + */ +public class SwitchExpressionCleanup implements ISimpleCleanUp { + + /* (non-Javadoc) + * @see org.eclipse.jdt.ls.core.internal.cleanup.ISimpleCleanUp#getIdentifier() + */ + @Override + public String getIdentifier() { + return "switchExpression"; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.ls.core.internal.cleanup.ISimpleCleanUp#createFix(org.eclipse.jdt.core.manipulation.CleanUpContextCore) + */ + @Override + public ICleanUpFixCore createFix(CleanUpContextCore context) throws CoreException { + CompilationUnit unit = context.getAST(); + if (unit == null) { + return null; + } + return SwitchExpressionsFixCore.createCleanUp(unit); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.ls.core.internal.cleanup.ISimpleCleanUp#getRequiredCompilerMarkers() + */ + @Override + public List getRequiredCompilerMarkers() { + return Collections.emptyList(); + } + +} diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/VariableDeclarationFixCleanup.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/VariableDeclarationFixCleanup.java new file mode 100644 index 0000000000..bdd072da4a --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/cleanup/VariableDeclarationFixCleanup.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2022 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ls.core.internal.cleanup; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.manipulation.CleanUpContextCore; +import org.eclipse.jdt.core.manipulation.ICleanUpFixCore; +import org.eclipse.jdt.internal.corext.fix.VariableDeclarationFixCore; + +/** + * Represents a cleanup that adds the 'final' modifier where possible + */ +public class VariableDeclarationFixCleanup implements ISimpleCleanUp { + + /* (non-Javadoc) + * @see org.eclipse.jdt.ls.core.internal.cleanup.ISimpleCleanUp#getIdentifier() + */ + @Override + public String getIdentifier() { + return "addFinalModifier"; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.ls.core.internal.cleanup.ISimpleCleanUp#createFix(org.eclipse.jdt.core.manipulation.CleanUpContextCore) + */ + @Override + public ICleanUpFixCore createFix(CleanUpContextCore context) throws CoreException { + CompilationUnit unit = context.getAST(); + if (unit == null) { + return null; + } + return VariableDeclarationFixCore.createCleanUp(unit, true, true, true); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.ls.core.internal.cleanup.ISimpleCleanUp#getRequiredCompilerMarkers() + */ + @Override + public List getRequiredCompilerMarkers() { + return Collections.emptyList(); + } + +} diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/cleanup/CleanUpsTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/cleanup/CleanUpsTest.java index 60237a3a3e..c06a5b66a2 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/cleanup/CleanUpsTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/cleanup/CleanUpsTest.java @@ -29,6 +29,7 @@ import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; +import org.eclipse.jdt.ls.core.internal.TextEditUtil; import org.eclipse.jdt.ls.core.internal.WorkspaceHelper; import org.eclipse.jdt.ls.core.internal.correction.TestOptions; import org.eclipse.jdt.ls.core.internal.managers.AbstractMavenBasedTest; @@ -57,9 +58,12 @@ public void setup() throws Exception { importProjects("maven/quickstart"); project = WorkspaceHelper.getProject("quickstart"); javaProject = JavaCore.create(project); + Hashtable options = TestOptions.getDefaultOptions(); + JavaCore.setComplianceOptions(JavaCore.VERSION_19, options); options.put(DefaultCodeFormatterConstants.FORMATTER_NUMBER_OF_EMPTY_LINES_TO_PRESERVE, String.valueOf(99)); javaProject.setOptions(options); + fSourceFolder = javaProject.getPackageFragmentRoot(javaProject.getProject().getFolder("src/main/java")); File src = fSourceFolder.getResource().getLocation().toFile(); src.mkdirs(); @@ -240,6 +244,235 @@ public void testInvertEqualsCleanUp() throws Exception { textEdits.get(0)); } + @Test + public void testAddFinalModifiersWherePossible() throws Exception { + String contents = "package test1;\n" // + + "\n" // + + "public class AddModifier {\n" // + + "\n" // + + "private String label1;\n" // + + "protected String label2;\n" // + + "public String label3;\n" // + + "private String label4 = \"\";\n" // + + "protected String label5 = \"\";\n" // + + "public String label6 = \"\";\n" // + + "private final String label7 = \"\";\n" // + + "\n" // + + "public void test(String foo) {\n" // + + " String label8, label9 = \"\";\n" // + + " String label10;\n" // + + " String label11 = \"\";\n" // + + " final String label12 = \"\";\n" // + + " }\n" // + + "}"; + + ICompilationUnit unit = pack1.createCompilationUnit("AddModifier.java", contents, false, monitor); + String uri = unit.getUnderlyingResource().getLocationURI().toString(); + List textEdits = registry.getEditsForAllActiveCleanUps(new TextDocumentIdentifier(uri), Arrays.asList("addFinalModifier"), monitor); + String actual = TextEditUtil.apply(unit, textEdits); + String expected = "package test1;\n" // + + "\n" // + + "public class AddModifier {\n" // + + "\n" // + + "private String label1;\n" // + + "protected String label2;\n" // + + "public String label3;\n" // + + "private final String label4 = \"\";\n" // + + "protected String label5 = \"\";\n" // + + "public String label6 = \"\";\n" // + + "private final String label7 = \"\";\n" // + + "\n" // + + "public void test(final String foo) {\n" // + + " final String label8, label9 = \"\";\n" // + + " final String label10;\n" // + + " final String label11 = \"\";\n" // + + " final String label12 = \"\";\n" // + + " }\n" // + + "}"; + + assertEquals(expected, actual); + } + + @Test + public void testConvertToSwitchExpression() throws Exception { + String contents = "package test1;\n" // + + "\n" // + + "public class SwitchExpression {\n" // + + " public void test() {\n" // + + " Day day2 = Day.THURSDAY;\n" // + + " String message2;\n" // + + " switch (day2) {\n" // + + " case SATURDAY:\n" // + + " case SUNDAY:\n" // + + " message2 = \"Weekend!\";\n" // + + " break;\n" // + + " case MONDAY:\n" // + + " case TUESDAY:\n" // + + " case WEDNESDAY:\n" // + + " case THURSDAY:\n" // + + " case FRIDAY:\n" // + + " message2 = \"Weekday\";\n" // + + " break;\n" // + + " default:\n" // + + " message2 = \"???\";\n" // + + " }\n" // + + " }\n" // + + "\n" // + + " public enum Day {\n" // + + " MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY\n" // + + " };\n" // + + "}"; + + ICompilationUnit unit = pack1.createCompilationUnit("SwitchExpression.java", contents, false, monitor); + String uri = unit.getUnderlyingResource().getLocationURI().toString(); + List textEdits = registry.getEditsForAllActiveCleanUps(new TextDocumentIdentifier(uri), Arrays.asList("switchExpression"), monitor); + String actual = TextEditUtil.apply(unit, textEdits); + String expected = "package test1;\n" // + + "\n" // + + "public class SwitchExpression {\n" // + + " public void test() {\n" // + + " Day day2 = Day.THURSDAY;\n" // + + " String message2 = switch (day2) {\n" // + + " case SATURDAY, SUNDAY -> \"Weekend!\";\n" // + + " case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> \"Weekday\";\n" // + + " default -> \"???\";\n" // + + " };\n" // + + " }\n" // + + "\n" // + + " public enum Day {\n" // + + " MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY\n" // + + " };\n" // + + "}"; + + assertEquals(expected, actual); + } + + @Test + public void testPatternMatchInstanceof() throws Exception { + String contents = "package test1;\n" // + + "\n" // + + "public class InstanceofPatternMatch {\n" // + + " public void test() {\n" // + + " Object str = new String(\"test\");\n" // + + " if (str instanceof String) {\n" // + + " String real = (String) str;\n" // + + " System.out.println(real.substring(0));\n" // + + " }\n" // + + " }\n" // + + "}"; + + ICompilationUnit unit = pack1.createCompilationUnit("InstanceofPatternMatch.java", contents, false, monitor); + String uri = unit.getUnderlyingResource().getLocationURI().toString(); + List textEdits = registry.getEditsForAllActiveCleanUps(new TextDocumentIdentifier(uri), Arrays.asList("instanceofPatternMatch"), monitor); + String actual = TextEditUtil.apply(unit, textEdits); + String expected = "package test1;\n" // + + "\n" // + + "public class InstanceofPatternMatch {\n" // + + " public void test() {\n" // + + " Object str = new String(\"test\");\n" // + + " if (str instanceof String real) {\n" // + + " System.out.println(real.substring(0));\n" // + + " }\n" // + + " }\n" // + + "}"; + + assertEquals(expected, actual); + } + + @Test + public void testLambdaExpression() throws Exception { + String contents = "package test1;\n" // + + "\n" // + + "import java.util.function.IntConsumer;\n" // + + "\n" // + + "public class LambdaExpression {\n" // + + " public void test() {\n" // + + " IntConsumer c = new IntConsumer() {\n" // + + " @Override\n" // + + " public void accept(int value) {\n" // + + " System.out.println(value);\n" // + + " }\n" // + + " };\n" // + + " }\n" // + + "}"; + + ICompilationUnit unit = pack1.createCompilationUnit("LambdaExpression.java", contents, false, monitor); + String uri = unit.getUnderlyingResource().getLocationURI().toString(); + List textEdits = registry.getEditsForAllActiveCleanUps(new TextDocumentIdentifier(uri), Arrays.asList("lambdaExpression"), monitor); + String actual = TextEditUtil.apply(unit, textEdits); + String expected = "package test1;\n" // + + "\n" // + + "import java.util.function.IntConsumer;\n" // + + "\n" // + + "public class LambdaExpression {\n" // + + " public void test() {\n" // + + " IntConsumer c = value -> System.out.println(value);\n" // + + " }\n" // + + "}"; + + assertEquals(expected, actual); + } + + @Test + public void testMultiCleanup() throws Exception { + String contents = "package test1;\n" + + "\n" + + "import java.io.File;\n" + + "import java.io.FileFilter;\n" + + "import java.util.Arrays;\n" + + "\n" + + "public class MutliCleanup {\n" + + " public void test() {\n" + + " String PATH = \"/this/is/some/path\";\n" + + " String MESSAGE = \"This is a message.\" +\n" + + " \"This message has multiple lines.\" +\n" + + " \"We can convert it to a text block\";\n" + + "\n" + + " Object[] obj = Arrays.asList(PATH).toArray();\n" + + " if (obj[0] instanceof String) {\n" + + " String tmp = (String) obj[0];\n" + + " File f = new File(tmp);\n" + + " File[] filtered = f.listFiles(new FileFilter() {\n" + + " @Override\n" + + " public boolean accept(File path) {\n" + + " return true;\n" + + " }\n" + + " });\n" + + " }\n" + + " }\n" + + "}\n" + + ""; + + ICompilationUnit unit = pack1.createCompilationUnit("MultiCleanup.java", contents, false, monitor); + String uri = unit.getUnderlyingResource().getLocationURI().toString(); + List textEdits = registry.getEditsForAllActiveCleanUps(new TextDocumentIdentifier(uri), Arrays.asList("lambdaExpression", "instanceofPatternMatch", "stringConcatToTextBlock", "addFinalModifier"), monitor); + String actual = TextEditUtil.apply(unit, textEdits); + String expected = "package test1;\n" + + "\n" + + "import java.io.File;\n" + + "import java.io.FileFilter;\n" + + "import java.util.Arrays;\n" + + "\n" + + "public class MutliCleanup {\n" + + " public void test() {\n" + + " final String PATH = \"/this/is/some/path\";\n" + + " final String MESSAGE = \"\"\"\n" + + " This is a message.\\\n" + + " This message has multiple lines.\\\n" + + " We can convert it to a text block\"\"\";\n" + + "\n" + + " final Object[] obj = Arrays.asList(PATH).toArray();\n" + + " if (obj[0] instanceof final String tmp) {\n" + + " final File f = new File(tmp);\n" + + " final File[] filtered = f.listFiles((FileFilter) path -> true);\n" + + " }\n" + + " }\n" + + "}\n" + + ""; + + assertEquals(expected, actual); + } + private static TextEdit te(String contents, Range range) { TextEdit textEdit = new TextEdit(); textEdit.setNewText(contents);