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

map extract refactorings to code action kinds #909

Merged
merged 1 commit into from
Dec 18, 2018
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
@@ -0,0 +1,49 @@
/*******************************************************************************
* Copyright (c) 2018 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 v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal;

import org.eclipse.lsp4j.CodeActionKind;

/**
* jdt.ls specific Code Action kinds, extending {@link CodeActionKind}
* hierarchies.
*
* @author Fred Bricon
*
*/
public interface JavaCodeActionKind {

/**
* Base kind for "generate" source actions
*/
public static final String SOURCE_GENERATE = CodeActionKind.Source + ".generate";

/**
* Generate accessors kind
*/
public static final String SOURCE_GENERATE_ACCESSORS = SOURCE_GENERATE + ".accessors";

/**
* Extract to method kind
*/
public static final String REFACTOR_EXTRACT_METHOD = CodeActionKind.RefactorExtract + ".function";// using `.function` instead of `.method` to match existing keybindings

/**
* Extract to constant kind
*/
public static final String REFACTOR_EXTRACT_CONSTANT = CodeActionKind.RefactorExtract + ".constant";

/**
* Extract to variable kind
*/
public static final String REFACTOR_EXTRACT_VARIABLE = CodeActionKind.RefactorExtract + ".variable";

}
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public List<Either<Command, CodeAction>> getCodeActionCommands(CodeActionParams
try {
for (CUCorrectionProposal proposal : candidates) {
Optional<Either<Command, CodeAction>> codeActionFromProposal = getCodeActionFromProposal(proposal, params.getContext());
if (codeActionFromProposal.isPresent()) {
if (codeActionFromProposal.isPresent() && !$.contains(codeActionFromProposal.get())) {
$.add(codeActionFromProposal.get());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
import org.eclipse.jdt.internal.corext.fix.LinkedProposalModelCore;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.ui.text.correction.IProblemLocationCore;
import org.eclipse.jdt.ls.core.internal.JavaCodeActionKind;
import org.eclipse.jdt.ls.core.internal.corext.fix.LambdaExpressionsCleanUp;
import org.eclipse.jdt.ls.core.internal.corext.fix.LambdaExpressionsFix;
import org.eclipse.jdt.ls.core.internal.corext.refactoring.code.ExtractConstantRefactoring;
Expand Down Expand Up @@ -453,7 +454,7 @@ private static boolean getExtractMethodProposal(IInvocationContext context, ASTN
extractMethodRefactoring.setLinkedProposalModel(linkedProposalModel);

int relevance = problemsAtLocation ? IProposalRelevance.EXTRACT_METHOD_ERROR : IProposalRelevance.EXTRACT_METHOD;
RefactoringCorrectionProposal proposal = new RefactoringCorrectionProposal(label, CodeActionKind.RefactorExtract, cu, extractMethodRefactoring, relevance);
RefactoringCorrectionProposal proposal = new RefactoringCorrectionProposal(label, JavaCodeActionKind.REFACTOR_EXTRACT_METHOD, cu, extractMethodRefactoring, relevance);
proposal.setLinkedProposalModel(linkedProposalModel);
proposals.add(proposal);
}
Expand Down Expand Up @@ -538,7 +539,7 @@ private static boolean getExtractVariableProposal(IInvocationContext context, bo
} else {
relevance = IProposalRelevance.EXTRACT_LOCAL_ALL;
}
RefactoringCorrectionProposal proposal = new RefactoringCorrectionProposal(label, CodeActionKind.RefactorExtract, cu, extractTempRefactoring, relevance) {
RefactoringCorrectionProposal proposal = new RefactoringCorrectionProposal(label, JavaCodeActionKind.REFACTOR_EXTRACT_VARIABLE, cu, extractTempRefactoring, relevance) {
@Override
protected void init(Refactoring refactoring) throws CoreException {
ExtractTempRefactoring etr = (ExtractTempRefactoring) refactoring;
Expand All @@ -565,7 +566,7 @@ protected void init(Refactoring refactoring) throws CoreException {
} else {
relevance = IProposalRelevance.EXTRACT_LOCAL;
}
RefactoringCorrectionProposal proposal = new RefactoringCorrectionProposal(label, CodeActionKind.RefactorExtract, cu, extractTempRefactoringSelectedOnly, relevance) {
RefactoringCorrectionProposal proposal = new RefactoringCorrectionProposal(label, JavaCodeActionKind.REFACTOR_EXTRACT_VARIABLE, cu, extractTempRefactoringSelectedOnly, relevance) {
@Override
protected void init(Refactoring refactoring) throws CoreException {
ExtractTempRefactoring etr = (ExtractTempRefactoring) refactoring;
Expand All @@ -591,7 +592,7 @@ protected void init(Refactoring refactoring) throws CoreException {
} else {
relevance = IProposalRelevance.EXTRACT_CONSTANT;
}
RefactoringCorrectionProposal proposal = new RefactoringCorrectionProposal(label, CodeActionKind.RefactorExtract, cu, extractConstRefactoring, relevance) {
RefactoringCorrectionProposal proposal = new RefactoringCorrectionProposal(label, JavaCodeActionKind.REFACTOR_EXTRACT_CONSTANT, cu, extractConstRefactoring, relevance) {
@Override
protected void init(Refactoring refactoring) throws CoreException {
ExtractConstantRefactoring etr = (ExtractConstantRefactoring) refactoring;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.manipulation.OrganizeImportsOperation;
import org.eclipse.jdt.internal.ui.text.correction.IProblemLocationCore;
import org.eclipse.jdt.ls.core.internal.JavaCodeActionKind;
import org.eclipse.jdt.ls.core.internal.codemanipulation.GenerateGetterSetterOperation;
import org.eclipse.jdt.ls.core.internal.corrections.CorrectionMessages;
import org.eclipse.jdt.ls.core.internal.corrections.IInvocationContext;
Expand All @@ -35,8 +36,6 @@
import org.eclipse.text.edits.TextEdit;

public class SourceAssistProcessor {
public static final String SOURCE_ACTION_GENERATE_KIND = CodeActionKind.Source + ".generate";
public static final String SOURCE_ACTION_GENERATE_ACCESSORS_KIND = SOURCE_ACTION_GENERATE_KIND + ".accessors";

public List<CUCorrectionProposal> getAssists(IInvocationContext context, IProblemLocationCore[] locations) {
ArrayList<CUCorrectionProposal> resultingCollections = new ArrayList<>();
Expand Down Expand Up @@ -77,7 +76,7 @@ private static void getGetterSetterProposal(IInvocationContext context, List<CUC
}

ICompilationUnit unit = context.getCompilationUnit();
CUCorrectionProposal proposal = new CUCorrectionProposal(ActionMessages.GenerateGetterSetterAction_label, SOURCE_ACTION_GENERATE_ACCESSORS_KIND, unit, null, IProposalRelevance.GENERATE_GETTER_AND_SETTER) {
CUCorrectionProposal proposal = new CUCorrectionProposal(ActionMessages.GenerateGetterSetterAction_label, JavaCodeActionKind.SOURCE_GENERATE_ACCESSORS, unit, null, IProposalRelevance.GENERATE_GETTER_AND_SETTER) {

@Override
protected void addEdits(IDocument document, TextEdit editRoot) throws CoreException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void testAbstractMethodInConcreteClass() throws Exception {
buf.append("}\n");
Expected e3 = new Expected("Remove method body", buf.toString());

assertCodeActions(cu, e1, e2, e2, e3);
assertCodeActions(cu, e1, e2, e3);
}

@Test
Expand Down Expand Up @@ -184,7 +184,7 @@ public void testAbstractMethodInEnum() throws Exception {
}

@Test
public void testAbstarctMethodInEnum2() throws Exception {
public void testAbstractMethodInEnum2() throws Exception {
IPackageFragment pack = fSourceFolder.createPackageFragment("test", false, null);
StringBuilder buf = new StringBuilder();
buf.append("package test;\n");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
Expand Down Expand Up @@ -63,25 +65,18 @@ public class AbstractQuickFixTest extends AbstractProjectsManagerBasedTest {
protected void assertCodeActionExists(ICompilationUnit cu, Expected expected) throws Exception {
List<Either<Command, CodeAction>> codeActions = evaluateCodeActions(cu);
for (Either<Command, CodeAction> c : codeActions) {
String actual = evaluateCodeActionCommand(c);
if (expected.content.equals(actual)) {
assertEquals(expected.name, getCommand(c).getTitle());
if (Objects.equals(expected.name, getTitle(c))) {
expected.assertEquivalent(c);
return;
}
}
String res = "";
for (Either<Command, CodeAction> command : codeActions) {
if (res.length() > 0) {
res += '\n';
}
res += getCommand(command).getTitle();
}
assertEquals("Not found.", expected.name, res);
String allCommands = codeActions.stream().map(a -> getTitle(a)).collect(Collectors.joining("\n"));
fail(expected.name + " not found in " + allCommands);
}

protected void assertCodeActionNotExists(ICompilationUnit cu, String label) throws Exception {
List<Either<Command, CodeAction>> codeActionCommands = evaluateCodeActions(cu);
assertFalse("'" + label + "' should not be added to the code actions", codeActionCommands.stream().filter(ca -> getCommand(ca).getTitle().equals(label)).findAny().isPresent());
assertFalse("'" + label + "' should not be added to the code actions", codeActionCommands.stream().filter(ca -> getTitle(ca).equals(label)).findAny().isPresent());
}

protected void assertCodeActions(ICompilationUnit cu, Collection<Expected> expected) throws Exception {
Expand All @@ -91,36 +86,31 @@ protected void assertCodeActions(ICompilationUnit cu, Collection<Expected> expec
protected void assertCodeActions(ICompilationUnit cu, Expected... expecteds) throws Exception {
List<Either<Command, CodeAction>> codeActions = evaluateCodeActions(cu);
if (codeActions.size() < expecteds.length) {
String res = "";
for (Either<Command, CodeAction> command : codeActions) {
res += " '" + getCommand(command).getTitle() + "'";
}
String res = codeActions.stream().map(a -> ("'" + getTitle(a) + "'")).collect(Collectors.joining(","));
assertEquals("Number of code actions: " + res, expecteds.length, codeActions.size());
}

Map<String, Expected> expectedActions = new HashMap<>();
Map<String, Expected> expectedActions = Stream.of(expecteds).collect(Collectors.toMap(Expected::getName, Function.identity()));
Map<String, Either<Command, CodeAction>> actualActions = codeActions.stream().collect(Collectors.toMap(this::getTitle, Function.identity()));

for (Expected expected : expecteds) {
for (Either<Command, CodeAction> command : codeActions) {
if (Objects.equals(getCommand(command).getTitle(), expected.name)) {
expectedActions.put(expected.name, expected);
break;
}
}
assertEquals("Should prompt code action: " + expected.name, expectedActions.containsKey(expected.name), true);
Either<Command, CodeAction> action = actualActions.get(expected.name);
assertNotNull("Should prompt code action: " + expected.name, action);
expected.assertEquivalent(action);
}

int k = 0;
String aStr = "", eStr = "", testContent = "";
for (Either<Command, CodeAction> c : codeActions) {
String title = getCommand(c).getTitle();
if (expectedActions.containsKey(title)) {
String title = getTitle(c);
Expected e = expectedActions.get(title);
if (e != null) {
String actual = evaluateCodeActionCommand(c);
Expected e = expectedActions.get(title);
if (!Objects.equals(e.content, actual)) {
aStr += '\n' + title + '\n' + actual;
eStr += '\n' + e.name + '\n' + e.content;
}
testContent += generateTest(actual, getCommand(c).getTitle(), k);
testContent += generateTest(actual, getTitle(c), k);
k++;
}
}
Expand Down Expand Up @@ -171,10 +161,35 @@ private static void wrapInBufAppend(String curr, StringBuilder buf) {
public class Expected {
String name;
String content;
String kind;
private static final String ALL_KINDS = "*";

public Expected(String name, String content) {
this(name, content, ALL_KINDS);
}

public Expected(String name, String content, String kind) {
this.content = content;
this.name = name;
this.kind = kind;
}

public String getName() {
return name;
}

/**
* Checks if the action has the same title as this. If it has, then assert that
* that action is equivalent to this in kind and content.
*/
public void assertEquivalent(Either<Command, CodeAction> action) throws Exception {
String title = getTitle(action);
assertEquals("Unexpected command :", name, title);
if (!ALL_KINDS.equals(kind) && action.isRight()) {
assertEquals(title + " has the wrong kind ", kind, action.getRight().getKind());
}
String actionContent = evaluateCodeActionCommand(action);
assertEquals(title + " has the wrong content ", content, actionContent);
}
}

Expand Down Expand Up @@ -229,7 +244,7 @@ protected List<Either<Command, CodeAction>> evaluateCodeActions(ICompilationUnit
List<Either<Command, CodeAction>> filteredList = new ArrayList<>();
for (Either<Command, CodeAction> codeAction : codeActions) {
for (String str : this.ignoredCommands) {
if (getCommand(codeAction).getTitle().matches(str)) {
if (getTitle(codeAction).matches(str)) {
filteredList.add(codeAction);
break;
}
Expand Down Expand Up @@ -285,4 +300,8 @@ public Command getCommand(Either<Command, CodeAction> codeAction) {
return codeAction.isLeft() ? codeAction.getLeft() : codeAction.getRight().getCommand();
}

public String getTitle(Either<Command, CodeAction> codeAction) {
return getCommand(codeAction).getTitle();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public void testConvertVarTypeToResolvedType() throws Exception {
buf.append("}\n");
ICompilationUnit cu = pack1.createCompilationUnit("Test.java", buf.toString(), false, null);
List<Either<Command, CodeAction>> codeActions = evaluateCodeActions(cu);
Either<Command, CodeAction> codeAction = codeActions.stream().filter(c -> getCommand(c).getTitle().matches("Change type of 'name' to 'String'")).findFirst().orElse(null);
Either<Command, CodeAction> codeAction = codeActions.stream().filter(c -> getTitle(c).matches("Change type of 'name' to 'String'")).findFirst().orElse(null);
assertNotNull(codeAction);
}

Expand All @@ -68,7 +68,7 @@ public void testConvertResolvedTypeToVar() throws Exception {
buf.append("}\n");
ICompilationUnit cu = pack1.createCompilationUnit("Test.java", buf.toString(), false, null);
List<Either<Command, CodeAction>> commands = evaluateCodeActions(cu);
Either<Command, CodeAction> codeAction = commands.stream().filter(c -> getCommand(c).getTitle().matches("Change type of 'name' to 'var'")).findFirst().orElse(null);
Either<Command, CodeAction> codeAction = commands.stream().filter(c -> getTitle(c).matches("Change type of 'name' to 'var'")).findFirst().orElse(null);
assertNotNull(codeAction);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3792,6 +3792,7 @@ public void testSuperMethodLessArguments() throws Exception {
}

@Test
@Ignore("'Add parentheses around cast' removes the cast instead!")
public void testMissingCastParents1() throws Exception {
IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null);

Expand All @@ -3817,6 +3818,7 @@ public void testMissingCastParents1() throws Exception {
}

@Test
@Ignore("'Add parentheses around cast' removes the cast instead!")
public void testMissingCastParents2() throws Exception {
IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null);

Expand All @@ -3842,6 +3844,7 @@ public void testMissingCastParents2() throws Exception {
}

@Test
@Ignore("'Add parentheses around cast' removes the cast instead!")
public void testMissingCastParents3() throws Exception {
IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2437,8 +2437,8 @@ public void testBug300() throws Exception {

buf = new StringBuilder();
buf.append("package test1;\n");
buf.append("public class Message {\n");
buf.append(" public Object z;\n");
buf.append("public class Message {\n\n");
buf.append(" public static Object z;\n");
buf.append("}\n");
Expected e1 = new Expected("Create field 'z' in type 'Message'", buf.toString());

Expand Down
Loading