Skip to content

Commit

Permalink
Add Quickfix 'UninitializedBlankFinalField'
Browse files Browse the repository at this point in the history
Signed-off-by: Snjezana Peco <[email protected]>
  • Loading branch information
snjeza committed Jan 26, 2024
1 parent d8643fc commit 4a7d0ae
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.eclipse.jdt.internal.ui.text.correction.IInvocationContextCore;
import org.eclipse.jdt.internal.ui.text.correction.IProblemLocationCore;
import org.eclipse.jdt.internal.ui.text.correction.IProposalRelevance;
import org.eclipse.jdt.internal.ui.text.correction.UnInitializedFinalFieldBaseSubProcessor;
import org.eclipse.jdt.internal.ui.text.correction.proposals.ReplaceCorrectionProposalCore;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.AddImportCorrectionProposal;
Expand Down Expand Up @@ -158,6 +159,10 @@ private void process(CodeActionParams params, IInvocationContextCore context, IP
case IProblem.UnresolvedVariable:
UnresolvedElementsSubProcessor.getVariableProposals(context, problem, null, proposals);
break;
case IProblem.UninitializedBlankFinalField:
UnInitializedFinalFieldBaseSubProcessor<ProposalKindWrapper> processor = new UnInitializedFinalFieldSubProcessor();
processor.addProposals(context, problem, proposals);
break;
case IProblem.AmbiguousType:
case IProblem.JavadocAmbiguousType:
UnresolvedElementsSubProcessor.getAmbiguousTypeReferenceProposals(context, problem, proposals);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright (c) 2024 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.corrections;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.internal.ui.text.correction.IProblemLocationCore;
import org.eclipse.jdt.internal.ui.text.correction.IProposalRelevance;
import org.eclipse.jdt.internal.ui.text.correction.UnInitializedFinalFieldBaseSubProcessor;
import org.eclipse.jdt.internal.ui.text.correction.proposals.InitializeFinalFieldProposalCore;
import org.eclipse.jdt.ls.core.internal.handlers.CodeActionHandler;
import org.eclipse.lsp4j.CodeActionKind;

/**
* @author snjeza
*
*/
public class UnInitializedFinalFieldSubProcessor extends UnInitializedFinalFieldBaseSubProcessor<ProposalKindWrapper> {

@Override
protected ProposalKindWrapper createInitializeFinalFieldProposal(IProblemLocationCore problem, ICompilationUnit targetCU, SimpleName node, IVariableBinding targetBinding, int createConstructor) {
InitializeFinalFieldProposalCore proposal = new InitializeFinalFieldProposalCore(problem, targetCU, node, targetBinding, IProposalRelevance.CREATE_CONSTRUCTOR);
return CodeActionHandler.wrap(proposal, CodeActionKind.QuickFix);
}

@Override
protected ProposalKindWrapper createInitializeFinalFieldProposal(IProblemLocationCore problem, ICompilationUnit targetCU, MethodDeclaration node, int createConstructor, int updateAtConstructor) {
InitializeFinalFieldProposalCore proposal = new InitializeFinalFieldProposalCore(problem, targetCU, node, IProposalRelevance.CREATE_CONSTRUCTOR, InitializeFinalFieldProposalCore.UPDATE_AT_CONSTRUCTOR);
return CodeActionHandler.wrap(proposal, CodeActionKind.QuickFix);
}

@Override
protected ProposalKindWrapper conditionallyCreateInitializeFinalFieldProposal(IProblemLocationCore problem, ICompilationUnit targetCU, MethodDeclaration node, int createConstructor, int updateAtConstructor) {
InitializeFinalFieldProposalCore initializeFinalFieldProposal = new InitializeFinalFieldProposalCore(problem, targetCU, node, IProposalRelevance.CREATE_CONSTRUCTOR, InitializeFinalFieldProposalCore.UPDATE_CONSTRUCTOR_NEW_PARAMETER);
try {
if (initializeFinalFieldProposal.hasProposal()) {
return CodeActionHandler.wrap(initializeFinalFieldProposal, CodeActionKind.QuickFix);
}
} catch (CoreException ce) {
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ public static List<Diagnostic> toDiagnosticsArray(IOpenable openable, List<IProb
diag.setCode(Integer.toString(problem.getID()));
diag.setSeverity(convertSeverity(problem));
diag.setRange(convertRange(openable, problem));
if (problem.getID() == IProblem.UndefinedName || problem.getID() == IProblem.UndefinedType) {
if (problem.getID() == IProblem.UndefinedName || problem.getID() == IProblem.UndefinedType || problem.getID() == IProblem.UninitializedBlankFinalField) {
diag.setData(problem.getArguments());
}
if (isDiagnosticTagSupported) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,11 @@ public static IProblemLocationCore[] getProblemLocationCores(ICompilationUnit un
arguments.add(e.getAsString());
}
}
if (diagnostic.getData() instanceof String[] data) {
for (String s : data) {
arguments.add(s);
}
}
locations[i] = new ProblemLocationCore(start, end - start, problemId, arguments.toArray(new String[0]), isError, IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
}
return locations;
Expand Down
2 changes: 1 addition & 1 deletion org.eclipse.jdt.ls.target/org.eclipse.jdt.ls.tp.target
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<unit id="org.eclipse.sdk.feature.group" version="0.0.0"/>
<unit id="org.mockito.mockito-core" version="0.0.0"/>
<unit id="org.apache.commons.commons-io" version="0.0.0"/>
<repository location="https://download.eclipse.org/eclipse/updates/4.31-I-builds/I20240112-1800/"/>
<repository location="https://download.eclipse.org/eclipse/updates/4.31-I-builds/I20240117-1800/"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.xtext.xbase.lib" version="0.0.0"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright (c) 2020 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
* https://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.correction;

import static org.junit.Assert.assertNotNull;

import java.util.List;
import java.util.Map;

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.core.JavaCore;
import org.eclipse.jdt.ls.core.internal.JavaCodeActionKind;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.CodeActionKind;
import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.junit.Before;
import org.junit.Test;

public class UnInitializedFinalFieldQuickFixTest extends AbstractQuickFixTest {

private IJavaProject javaProject;
private IPackageFragmentRoot sourceFolder;

@Before
public void setup() throws Exception {
javaProject = newEmptyProject();
Map<String, String> options = TestOptions.getDefaultOptions();
options.put(JavaCore.COMPILER_PB_NO_EFFECT_ASSIGNMENT, JavaCore.IGNORE);
options.put(JavaCore.COMPILER_PB_INDIRECT_STATIC_ACCESS, JavaCore.ERROR);
javaProject.setOptions(options);
sourceFolder = javaProject.getPackageFragmentRoot(javaProject.getProject().getFolder("src"));
setIgnoredKind(CodeActionKind.Refactor, JavaCodeActionKind.QUICK_ASSIST, JavaCodeActionKind.SOURCE_OVERRIDE_METHODS, JavaCodeActionKind.SOURCE_GENERATE_TO_STRING, JavaCodeActionKind.SOURCE_GENERATE_CONSTRUCTORS,
JavaCodeActionKind.SOURCE_GENERATE_FINAL_MODIFIERS, JavaCodeActionKind.SOURCE_GENERATE_ACCESSORS, JavaCodeActionKind.REFACTOR_EXTRACT_FIELD, JavaCodeActionKind.REFACTOR_EXTRACT_VARIABLE,
JavaCodeActionKind.REFACTOR_INTRODUCE_PARAMETER, CodeActionKind.RefactorInline);
}

@Test
public void testUnInitializedFinalField() throws Exception {
IPackageFragment pack1 = sourceFolder.createPackageFragment("org.sample", false, null);
StringBuilder buf = new StringBuilder();
buf.append("package org.sample;\n");
buf.append("\n");
buf.append("public class Foo {\n");
buf.append(" static final int i;\n");
buf.append(" final int j;\n");
buf.append(" static {\n");
buf.append(" assert (i = 0) == 0;\n");
buf.append(" System.out.println(i);\n");
buf.append(" }\n");
buf.append("\n");
buf.append(" public Foo() {\n");
buf.append(" }\n");
buf.append("}\n");
ICompilationUnit cu = pack1.createCompilationUnit("Foo.java", buf.toString(), false, null);
List<Either<Command, CodeAction>> codeActions = evaluateCodeActions(cu);
Either<Command, CodeAction> codeAction = codeActions.stream().filter(c -> getTitle(c).matches("Initialize final field 'i' at declaration.")).findFirst().orElse(null);
assertNotNull(codeAction);
buf = new StringBuilder();
buf.append("package org.sample;\n");
buf.append("\n");
buf.append("public class Foo {\n");
buf.append(" static final int i = 0;\n");
buf.append(" final int j;\n");
buf.append(" static {\n");
buf.append(" assert (i = 0) == 0;\n");
buf.append(" System.out.println(i);\n");
buf.append(" }\n");
buf.append("\n");
buf.append(" public Foo() {\n");
buf.append(" }\n");
buf.append("}\n");
Expected expected = new Expected("Initialize final field 'i' at declaration.", buf.toString(), CodeActionKind.QuickFix);
Range range = new Range(new Position(4, 22), new Position(4, 22));
assertCodeActions(cu, range, expected);
}

}

0 comments on commit 4a7d0ae

Please sign in to comment.