Skip to content

Commit

Permalink
Add 'Make Static' refactoring.
Browse files Browse the repository at this point in the history
- Convert instance methods into static methods when possible
- Add testcases

Signed-off-by: Roland Grunberg <[email protected]>
  • Loading branch information
rgrunber committed Feb 28, 2025
1 parent 59872de commit 75e72a4
Show file tree
Hide file tree
Showing 2 changed files with 223 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,12 @@
import org.eclipse.jdt.internal.corext.fix.LambdaExpressionsFixCore;
import org.eclipse.jdt.internal.corext.fix.LinkedProposalModelCore;
import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTesterCore;
import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
import org.eclipse.jdt.internal.corext.refactoring.code.ConvertAnonymousToNestedRefactoring;
import org.eclipse.jdt.internal.corext.refactoring.code.InlineConstantRefactoring;
import org.eclipse.jdt.internal.corext.refactoring.code.InlineMethodRefactoring;
import org.eclipse.jdt.internal.corext.refactoring.code.InlineTempRefactoring;
import org.eclipse.jdt.internal.corext.refactoring.code.MakeStaticRefactoring;
import org.eclipse.jdt.internal.corext.refactoring.structure.ImportRemover;
import org.eclipse.jdt.internal.corext.refactoring.surround.SurroundWithTryCatchRefactoring;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
Expand Down Expand Up @@ -223,12 +225,14 @@ public List<ProposalKindWrapper> getProposals(CodeActionParams params, IInvocati
if (monitor != null && monitor.isCanceled()) {
return Collections.emptyList();
}
getMakeMethodStaticRefactoringProposal(params, context, coveringNode, proposals, monitor);
}
return proposals;
}
return Collections.emptyList();
}


private boolean getIntroduceParameterProposals(CodeActionParams params, IInvocationContext context, ASTNode coveringNode, IProblemLocation[] locations, ArrayList<ProposalKindWrapper> resultingCollections) throws CoreException {
if (resultingCollections == null) {
return false;
Expand Down Expand Up @@ -1178,4 +1182,33 @@ private boolean getSurroundWithTryCatchProposal(IInvocationContext context, Coll

return false;
}

private boolean getMakeMethodStaticRefactoringProposal(CodeActionParams params, IInvocationContext context, ASTNode coveringNode, ArrayList<ProposalKindWrapper> proposals, IProgressMonitor monitor) {
MakeStaticRefactoring refactoring = new MakeStaticRefactoring(context.getCompilationUnit(), context.getSelectionOffset(), context.getSelectionLength());
try {
if (refactoring != null && refactoring.checkInitialConditions(new NullProgressMonitor()).isOK()) {
String label = RefactoringCoreMessages.MakeStaticRefactoring_name;
int relevance = IProposalRelevance.CHANGE_METHOD_SIGNATURE;
ChangeCorrectionProposalCore proposal = new ChangeCorrectionProposalCore(label, null /*create.getChange()*/, relevance) {
@Override
public Change getChange() throws CoreException {
CheckConditionsOperation check = new CheckConditionsOperation(refactoring, CheckConditionsOperation.FINAL_CONDITIONS);
final CreateChangeOperation create = new CreateChangeOperation(check, RefactoringStatus.FATAL);
try {
create.run(new NullProgressMonitor());
return create.getChange();
} catch (CoreException e) {
JavaLanguageServerPlugin.log(e);
}
return new NullChange();
}
};
proposals.add(CodeActionHandler.wrap(proposal, CodeActionKind.RefactorInline));
}
} catch (JavaModelException e) {
return false;
}
return true;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/*******************************************************************************
* Copyright (c) 2025 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.refactoring;

import java.util.Hashtable;

import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
import org.eclipse.jdt.ls.core.internal.CodeActionUtil;
import org.eclipse.jdt.ls.core.internal.correction.AbstractSelectionTest;
import org.eclipse.jdt.ls.core.internal.correction.TestOptions;
import org.eclipse.lsp4j.CodeActionKind;
import org.junit.Before;
import org.junit.Test;

public class MakeStaticTest extends AbstractSelectionTest {

private static final String MAKE_STATIC = RefactoringCoreMessages.MakeStaticRefactoring_name;

private IJavaProject testProject;

private IPackageFragmentRoot testSourceFolder;

@Before
public void setup() throws Exception {
testProject = newEmptyProject();
Hashtable<String, String> options = TestOptions.getDefaultOptions();

testProject.setOptions(options);
testSourceFolder = testProject.getPackageFragmentRoot(testProject.getProject().getFolder("src"));
}

@Test
public void testArrayParameterAndReturnType() throws Exception {
IPackageFragment pack1 = testSourceFolder.createPackageFragment("", false, null);

String input = "public class Foo {\n"
+ "\n"
+ " public String[] bar(String[] ending) {\n"
+ " String[] j = new String[] {ending[0], ending[1]};\n"
+ " return j;\n"
+ " }\n"
+ "\n"
+ " public static void foo() {\n"
+ " Foo instance = new Foo();\n"
+ " String[] stringArray = new String[] {\"bar\", \"bar\"};\n"
+ " String[] j = instance.bar(stringArray);\n"
+ " }\n"
+ "}";

ICompilationUnit cu = pack1.createCompilationUnit("Foo.java", input, false, null);

String output = "public class Foo {\n"
+ "\n"
+ " public static String[] bar(String[] ending) {\n"
+ " String[] j = new String[] {ending[0], ending[1]};\n"
+ " return j;\n"
+ " }\n"
+ "\n"
+ " public static void foo() {\n"
+ " Foo instance = new Foo();\n"
+ " String[] stringArray = new String[] {\"bar\", \"bar\"};\n"
+ " String[] j = Foo.bar(stringArray);\n"
+ " }\n"
+ "}";

Expected expected = new Expected(MAKE_STATIC, output, CodeActionKind.RefactorInline);
assertCodeActions(cu, CodeActionUtil.getRange(cu, "bar(String[] ending)", 0), expected);
}

@Test
public void testConcatenatedFieldAccessAndQualifiedNames() throws Exception {
IPackageFragment pack1 = testSourceFolder.createPackageFragment("", false, null);

String input = "public class Foo {\n"
+ " Foo foo;\n"
+ "\n"
+ " int i= 0;\n"
+ "\n"
+ " public void bar() {\n"
+ " //Field Access\n"
+ " this.foo.foo.foo.method();\n"
+ " this.getInstance().getInstance().method();\n"
+ " foo.getInstance().foo.getInstance().foo.method();\n"
+ " getInstance().foo.getInstance().foo.getInstance().method();\n"
+ "\n"
+ " this.foo.foo.foo.i++;\n"
+ " this.getInstance().getInstance().i++;\n"
+ " foo.getInstance().foo.getInstance().i++;\n"
+ " getInstance().foo.getInstance().foo.getInstance().i++;\n"
+ "\n"
+ " //Qualified Name\n"
+ " foo.foo.foo = foo.foo;\n"
+ " }\n"
+ "\n"
+ " public Foo getInstance() {\n"
+ " return this;\n"
+ " }\n"
+ "\n"
+ " public void method() {\n"
+ " }\n"
+ "}";

ICompilationUnit cu = pack1.createCompilationUnit("Foo.java", input, false, null);

String output = "public class Foo {\n"
+ " Foo foo;\n"
+ "\n"
+ " int i= 0;\n"
+ "\n"
+ " public static void bar(Foo foo) {\n"
+ " //Field Access\n"
+ " foo.foo.foo.foo.method();\n"
+ " foo.getInstance().getInstance().method();\n"
+ " foo.foo.getInstance().foo.getInstance().foo.method();\n"
+ " foo.getInstance().foo.getInstance().foo.getInstance().method();\n"
+ "\n"
+ " foo.foo.foo.foo.i++;\n"
+ " foo.getInstance().getInstance().i++;\n"
+ " foo.foo.getInstance().foo.getInstance().i++;\n"
+ " foo.getInstance().foo.getInstance().foo.getInstance().i++;\n"
+ "\n"
+ " //Qualified Name\n"
+ " foo.foo.foo.foo = foo.foo.foo;\n"
+ " }\n"
+ "\n"
+ " public Foo getInstance() {\n"
+ " return this;\n"
+ " }\n"
+ "\n"
+ " public void method() {\n"
+ " }\n"
+ "}";

Expected expected = new Expected(MAKE_STATIC, output, CodeActionKind.RefactorInline);
assertCodeActions(cu, CodeActionUtil.getRange(cu, "bar()", 0), expected);
}

@Test
public void testDuplicateParamName() throws Exception {
IPackageFragment pack1 = testSourceFolder.createPackageFragment("", false, null);

String input = "public class Foo {\n"
+ "\n"
+ " String j= \"\";\n"
+ "\n"
+ " public String bar(String foo) {\n"
+ " String i= this.j;\n"
+ " return i;\n"
+ " }\n"
+ "\n"
+ " public void method() {\n"
+ " String j= this.bar(\"bar\");\n"
+ " }\n"
+ "}";

ICompilationUnit cu = pack1.createCompilationUnit("Foo.java", input, false, null);

String output = "public class Foo {\n"
+ "\n"
+ " String j= \"\";\n"
+ "\n"
+ " public static String bar(Foo foo2, String foo) {\n"
+ " String i= foo2.j;\n"
+ " return i;\n"
+ " }\n"
+ "\n"
+ " public void method() {\n"
+ " String j= Foo.bar(this, \"bar\");\n"
+ " }\n"
+ "}";

Expected expected = new Expected(MAKE_STATIC, output, CodeActionKind.RefactorInline);
assertCodeActions(cu, CodeActionUtil.getRange(cu, "bar(String foo)", 0), expected);

}
}

0 comments on commit 75e72a4

Please sign in to comment.