Skip to content

Commit 43576bd

Browse files
Migrate new "Replace deprecated field" QuickFix from jdt.ui (#3637)
Co-authored-by: Fred Bricon <fbricon@gmail.com>
1 parent a59426e commit 43576bd

2 files changed

Lines changed: 263 additions & 0 deletions

File tree

org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/QuickFixProcessor.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.Comparator;
3030
import java.util.HashSet;
3131
import java.util.List;
32+
import java.util.Map;
3233
import java.util.Optional;
3334
import java.util.Set;
3435

@@ -39,12 +40,20 @@
3940
import org.eclipse.jdt.core.compiler.IProblem;
4041
import org.eclipse.jdt.core.dom.ASTNode;
4142
import org.eclipse.jdt.core.dom.CompilationUnit;
43+
import org.eclipse.jdt.core.dom.FieldAccess;
4244
import org.eclipse.jdt.core.dom.MethodInvocation;
45+
import org.eclipse.jdt.core.dom.QualifiedName;
46+
import org.eclipse.jdt.core.dom.SimpleName;
47+
import org.eclipse.jdt.core.dom.SuperFieldAccess;
4348
import org.eclipse.jdt.core.manipulation.CUCorrectionProposalCore;
4449
import org.eclipse.jdt.core.manipulation.ChangeCorrectionProposalCore;
50+
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
51+
import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
4552
import org.eclipse.jdt.internal.corext.fix.FixMessages;
4653
import org.eclipse.jdt.internal.corext.fix.IProposableFix;
4754
import org.eclipse.jdt.internal.corext.fix.InlineMethodFixCore;
55+
import org.eclipse.jdt.internal.corext.fix.ReplaceDeprecatedFieldFixCore;
56+
import org.eclipse.jdt.internal.ui.fix.ReplaceDeprecatedFieldCleanUpCore;
4857
import org.eclipse.jdt.internal.ui.text.correction.IProposalRelevance;
4958
import org.eclipse.jdt.internal.ui.text.correction.QuickAssistProcessorUtil;
5059
import org.eclipse.jdt.internal.ui.text.correction.UnInitializedFinalFieldBaseSubProcessor;
@@ -62,6 +71,7 @@
6271
import org.eclipse.jdt.ls.core.internal.handlers.CodeActionHandler;
6372
import org.eclipse.jdt.ls.core.internal.handlers.OrganizeImportsHandler;
6473
import org.eclipse.jdt.ls.core.internal.text.correction.ModifierCorrectionSubProcessor;
74+
import org.eclipse.jdt.ui.cleanup.CleanUpOptions;
6575
import org.eclipse.jdt.ui.text.java.IInvocationContext;
6676
import org.eclipse.jdt.ui.text.java.IProblemLocation;
6777
import org.eclipse.lsp4j.CodeActionKind;
@@ -518,6 +528,31 @@ private void process(CodeActionParams params, IInvocationContext context, IProbl
518528
}
519529
}
520530
break;
531+
case IProblem.UsingDeprecatedField:
532+
ASTNode deprecatedFieldNode = problem.getCoveredNode(context.getASTRoot());
533+
if (deprecatedFieldNode != null && !(deprecatedFieldNode instanceof QualifiedName)
534+
&& !(deprecatedFieldNode instanceof FieldAccess)
535+
&& !(deprecatedFieldNode instanceof SuperFieldAccess)) {
536+
ASTNode originalNode = deprecatedFieldNode;
537+
deprecatedFieldNode = ASTNodes.getFirstAncestorOrNull(deprecatedFieldNode, QualifiedName.class, FieldAccess.class, SuperFieldAccess.class);
538+
if (deprecatedFieldNode == null && originalNode instanceof SimpleName) {
539+
deprecatedFieldNode = originalNode;
540+
}
541+
}
542+
if (deprecatedFieldNode != null) {
543+
String replacement = QuickAssistProcessorUtil.getDeprecatedFieldReplacement(deprecatedFieldNode);
544+
if (replacement != null) {
545+
IProposableFix fix = ReplaceDeprecatedFieldFixCore.create(FixMessages.ReplaceDeprecatedField_msg, replacement, (CompilationUnit)deprecatedFieldNode.getRoot(), deprecatedFieldNode);
546+
if (fix != null) {
547+
Map<String, String> options = Map.of(CleanUpConstants.REPLACE_DEPRECATED_FIELDS, CleanUpOptions.TRUE);
548+
proposals.add(CodeActionHandler.wrap(
549+
new FixCorrectionProposalCore(fix, new ReplaceDeprecatedFieldCleanUpCore(options), IProposalRelevance.REPLACE_DEPRECATED_FIELD, context),
550+
CodeActionKind.QuickFix)
551+
);
552+
}
553+
}
554+
}
555+
break;
521556
// case IProblem.IsClassPathCorrect:
522557
// ReorgCorrectionsSubProcessor.getIncorrectBuildPathProposals(context,
523558
// problem, proposals);
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 IBM Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License 2.0
5+
* which accompanies this distribution, and is available at
6+
* https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* IBM Corporation - initial API and implementation
12+
*******************************************************************************/
13+
package org.eclipse.jdt.ls.core.internal.correction;
14+
15+
import java.util.Map;
16+
17+
import org.eclipse.jdt.core.ICompilationUnit;
18+
import org.eclipse.jdt.core.IJavaProject;
19+
import org.eclipse.jdt.core.IPackageFragment;
20+
import org.eclipse.jdt.core.IPackageFragmentRoot;
21+
import org.eclipse.jdt.core.JavaCore;
22+
import org.eclipse.jdt.internal.corext.fix.FixMessages;
23+
import org.eclipse.jdt.ls.core.internal.CodeActionUtil;
24+
import org.eclipse.lsp4j.Position;
25+
import org.eclipse.lsp4j.Range;
26+
import org.junit.Before;
27+
import org.junit.Test;
28+
29+
public class DeprecatedFieldQuickFixTest extends AbstractQuickFixTest {
30+
31+
private IJavaProject fJProject;
32+
private IPackageFragmentRoot fSourceFolder;
33+
34+
@Before
35+
public void setup() throws Exception {
36+
fJProject = newEmptyProject();
37+
Map<String, String> options = TestOptions.getDefaultOptions();
38+
options.put(JavaCore.COMPILER_PB_DEPRECATION, JavaCore.WARNING);
39+
fJProject.setOptions(options);
40+
fSourceFolder = fJProject.getPackageFragmentRoot(fJProject.getProject().getFolder("src"));
41+
}
42+
43+
@Test
44+
public void testReplaceDeprecatedField_externalInterface_staticAccess() throws Exception {
45+
IPackageFragment pack2 = fSourceFolder.createPackageFragment("test2", false, null);
46+
String str2 = """
47+
package test2;
48+
49+
public interface K {
50+
String field1 = "abc";
51+
String field2 = "def";
52+
}
53+
""";
54+
pack2.createCompilationUnit("K.java", str2, false, null);
55+
56+
IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null);
57+
String str1 = """
58+
package test1;
59+
60+
import test2.K;
61+
62+
public interface B {
63+
/**
64+
* @deprecated use {@link K#field2} instead
65+
*/
66+
@Deprecated
67+
String field = "blah";
68+
}
69+
""";
70+
pack1.createCompilationUnit("B.java", str1, false, null);
71+
72+
String str = """
73+
package test1;
74+
75+
class E {
76+
public void foo() {
77+
String x = B.field;
78+
System.out.println(x);
79+
}
80+
}
81+
""";
82+
83+
ICompilationUnit cu = pack1.createCompilationUnit("E.java", str, false, null);
84+
85+
String expected = """
86+
package test1;
87+
88+
import test2.K;
89+
90+
class E {
91+
public void foo() {
92+
String x = K.field2;
93+
System.out.println(x);
94+
}
95+
}
96+
""";
97+
98+
Range selection = CodeActionUtil.getRange(cu, "B.field");
99+
Expected e = new Expected(FixMessages.ReplaceDeprecatedField_msg, expected);
100+
assertCodeActions(cu, selection, e);
101+
}
102+
103+
@Test
104+
public void testReplaceDeprecatedField_externalInterface_innerClassAccess() throws Exception {
105+
IPackageFragment pack2 = fSourceFolder.createPackageFragment("test2", false, null);
106+
String str2 = """
107+
package test2;
108+
109+
public interface K {
110+
String field1 = "abc";
111+
String field2 = "def";
112+
}
113+
""";
114+
pack2.createCompilationUnit("K.java", str2, false, null);
115+
116+
IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null);
117+
String str1 = """
118+
package test1;
119+
120+
import test2.K;
121+
122+
public interface B {
123+
/**
124+
* @deprecated use {@link K#field2} instead
125+
*/
126+
@Deprecated
127+
String field = "blah";
128+
}
129+
""";
130+
pack1.createCompilationUnit("B.java", str1, false, null);
131+
132+
String str = """
133+
package test1;
134+
135+
class E {
136+
private class Z implements B {
137+
}
138+
139+
public void foo() {
140+
String x = new Z().field;
141+
System.out.println(x);
142+
}
143+
}
144+
""";
145+
146+
ICompilationUnit cu = pack1.createCompilationUnit("E.java", str, false, null);
147+
148+
String expected = """
149+
package test1;
150+
151+
import test2.K;
152+
153+
class E {
154+
private class Z implements B {
155+
}
156+
157+
public void foo() {
158+
String x = K.field2;
159+
System.out.println(x);
160+
}
161+
}
162+
""";
163+
164+
Range selection = CodeActionUtil.getRange(cu, "new Z().field");
165+
Expected e = new Expected(FixMessages.ReplaceDeprecatedField_msg, expected);
166+
assertCodeActions(cu, selection, e);
167+
}
168+
169+
@Test
170+
public void testReplaceDeprecatedField_selectionLengthOne() throws Exception {
171+
IPackageFragment pack2 = fSourceFolder.createPackageFragment("test2", false, null);
172+
String str2 = """
173+
package test2;
174+
175+
public interface K {
176+
String field1 = "abc";
177+
String field2 = "def";
178+
}
179+
""";
180+
pack2.createCompilationUnit("K.java", str2, false, null);
181+
182+
IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null);
183+
String str1 = """
184+
package test1;
185+
186+
import test2.K;
187+
188+
public interface B {
189+
/**
190+
* @deprecated use {@link K#field2} instead
191+
*/
192+
@Deprecated
193+
String field = "blah";
194+
}
195+
""";
196+
pack1.createCompilationUnit("B.java", str1, false, null);
197+
198+
String str = """
199+
package test1;
200+
201+
class E {
202+
public void foo() {
203+
String x = B.field;
204+
System.out.println(x);
205+
}
206+
}
207+
""";
208+
209+
ICompilationUnit cu = pack1.createCompilationUnit("E.java", str, false, null);
210+
Position start = CodeActionUtil.getRange(cu, "field").getStart();
211+
Range selection = new Range(new Position(start.getLine(), start.getCharacter() + 1), new Position(start.getLine(), start.getCharacter() + 2));
212+
213+
String expected = """
214+
package test1;
215+
216+
import test2.K;
217+
218+
class E {
219+
public void foo() {
220+
String x = K.field2;
221+
System.out.println(x);
222+
}
223+
}
224+
""";
225+
Expected e = new Expected(FixMessages.ReplaceDeprecatedField_msg, expected);
226+
assertCodeActions(cu, selection, e);
227+
}
228+
}

0 commit comments

Comments
 (0)