Skip to content

Bulk generate getter and setter #892

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

Merged
merged 4 commits into from
Dec 12, 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
5 changes: 3 additions & 2 deletions org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="3.12.0",
org.eclipse.jdt.apt.pluggable.core;bundle-version="1.2.0",
org.jboss.tools.maven.apt.core;bundle-version="1.3.0"
Export-Package: org.eclipse.jdt.ls.core.internal;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.codemanipulation;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.commands;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.contentassist;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.corext.codemanipulation;x-friends:="org.eclipse.jdt.ls.tests",
Expand All @@ -46,11 +47,11 @@ Export-Package: org.eclipse.jdt.ls.core.internal;x-friends:="org.eclipse.jdt.ls.
org.eclipse.jdt.ls.core.internal.corrections;x-internal:=true,
org.eclipse.jdt.ls.core.internal.corrections.proposals;x-internal:=true,
org.eclipse.jdt.ls.core.internal.handlers;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.highlighting;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.javadoc;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.lsp;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.managers;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.preferences;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.highlighting;x-friends:="org.eclipse.jdt.ls.tests"
org.eclipse.jdt.ls.core.internal.preferences;x-friends:="org.eclipse.jdt.ls.tests"
Bundle-ClassPath: lib/jsoup-1.9.2.jar,
lib/remark-1.0.0.jar,
.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*******************************************************************************
* Copyright (c) 2018 Microsoft Corporation 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:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/

package org.eclipse.jdt.ls.core.internal.codemanipulation;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.jdt.core.manipulation.CoreASTProvider;
import org.eclipse.jdt.internal.core.manipulation.StubUtility;
import org.eclipse.jdt.internal.corext.codemanipulation.GetterSetterUtil;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
import org.eclipse.text.edits.TextEdit;

public class GenerateGetterSetterOperation {
private final static int generateVisibility = Modifier.PUBLIC;
private final static boolean generateComments = true;

private final IType type;
private CompilationUnit astRoot;

public GenerateGetterSetterOperation(IType type, CompilationUnit astRoot) {
Assert.isNotNull(type);
this.type = type;
this.astRoot = astRoot;
}

public static boolean supportsGetterSetter(IType type) throws JavaModelException {
if (type == null || type.isAnnotation() || type.isInterface() || type.getCompilationUnit() == null) {
return false;
}

return true;
}

public TextEdit createTextEdit(IProgressMonitor monitor) throws OperationCanceledException, CoreException {
if (!supportsGetterSetter(type)) {
return null;
}

final ICompilationUnit unit = type.getCompilationUnit();
if (astRoot == null) {
astRoot = CoreASTProvider.getInstance().getAST(unit, CoreASTProvider.WAIT_YES, monitor);
}

final ASTRewrite astRewrite = ASTRewrite.create(astRoot.getAST());
ListRewrite listRewriter = null;
if (type.isAnonymous()) {
final ClassInstanceCreation creation = ASTNodes.getParent(NodeFinder.perform(astRoot, type.getNameRange()), ClassInstanceCreation.class);
if (creation != null) {
final AnonymousClassDeclaration declaration = creation.getAnonymousClassDeclaration();
if (declaration != null) {
listRewriter = astRewrite.getListRewrite(declaration, AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY);
}
}
} else {
final AbstractTypeDeclaration declaration = ASTNodes.getParent(NodeFinder.perform(astRoot, type.getNameRange()), AbstractTypeDeclaration.class);
if (declaration != null) {
listRewriter = astRewrite.getListRewrite(declaration, declaration.getBodyDeclarationsProperty());
}
}

if (listRewriter == null) {
return null;
}

generateGetterSetterMethods(listRewriter);
return astRewrite.rewriteAST();
}

private void generateGetterSetterMethods(ListRewrite listRewriter) throws OperationCanceledException, CoreException {
IField[] fields = type.getFields();
for (IField field : fields) {
int flags = field.getFlags();
if (!Flags.isEnum(flags)) {
if (GetterSetterUtil.getGetter(field) == null) {
insertMethod(field, listRewriter, AccessorKind.GETTER);
}

if (!Flags.isFinal(flags) && GetterSetterUtil.getSetter(field) == null) {
insertMethod(field, listRewriter, AccessorKind.SETTER);
}
}
}
}

private void insertMethod(IField field, ListRewrite rewrite, AccessorKind kind) throws CoreException {
IType type = field.getDeclaringType();
String delimiter = StubUtility.getLineDelimiterUsed(type);
int flags = generateVisibility | (field.getFlags() & Flags.AccStatic);
String stub;
if (kind == AccessorKind.GETTER) {
String name = GetterSetterUtil.getGetterName(field, null);
stub = GetterSetterUtil.getGetterStub(field, name, generateComments, flags);
} else {
String name = GetterSetterUtil.getSetterName(field, null);
stub = GetterSetterUtil.getSetterStub(field, name, generateComments, flags);
}

String formattedStub = CodeFormatterUtil.format(CodeFormatter.K_CLASS_BODY_DECLARATIONS, stub, 0, delimiter, type.getJavaProject().getOptions(true));
MethodDeclaration declaration = (MethodDeclaration) rewrite.getASTRewrite().createStringPlaceholder(formattedStub, ASTNode.METHOD_DECLARATION);
rewrite.insertLast(declaration, null);
}

enum AccessorKind {
GETTER, SETTER
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ public interface IProposalRelevance {
public static final int CREATE_CONSTANT= 4;

public static final int CHANGE_CLASS_TO_INTERFACE= 3;
public static final int GENERATE_GETTER_AND_SETTER = 3;
public static final int GENERATE_HASHCODE_AND_EQUALS= 3;
public static final int SIMILAR_TYPE= 3;
public static final int EXTRACT_LOCAL_ALL_ERROR= 3;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@ public boolean isSupportedCodeActionKind(String kind) {
&& capabilities.getTextDocument().getCodeAction().getCodeActionLiteralSupport() != null
&& capabilities.getTextDocument().getCodeAction().getCodeActionLiteralSupport().getCodeActionKind() != null
&& capabilities.getTextDocument().getCodeAction().getCodeActionLiteralSupport().getCodeActionKind().getValueSet() != null
&& capabilities.getTextDocument().getCodeAction().getCodeActionLiteralSupport().getCodeActionKind().getValueSet().contains(kind);
&& capabilities.getTextDocument().getCodeAction().getCodeActionLiteralSupport().getCodeActionKind().getValueSet()
.stream().filter(k -> kind.startsWith(k)).findAny().isPresent();
//@formatter:on
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright (c) 2018 Microsoft Corporation 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:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/

package org.eclipse.jdt.ls.core.internal.text.correction;

import org.eclipse.osgi.util.NLS;

public final class ActionMessages extends NLS {
private static final String BUNDLE_NAME = ActionMessages.class.getName();

private ActionMessages() {
// Do not instantiate
}

public static String GenerateGetterSetterAction_label;

static {
NLS.initializeMessages(BUNDLE_NAME, ActionMessages.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
###############################################################################
# Copyright (c) 2018 Microsoft Corporation 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:
# Microsoft Corporation - initial API and implementation
###############################################################################

GenerateGetterSetterAction_label=Generate Getters and Setters
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,16 @@

import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
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.codemanipulation.GenerateGetterSetterOperation;
import org.eclipse.jdt.ls.core.internal.corrections.CorrectionMessages;
import org.eclipse.jdt.ls.core.internal.corrections.IInvocationContext;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.CUCorrectionProposal;
Expand All @@ -28,11 +35,14 @@
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<>();

getOrganizeImportsProposal(context, resultingCollections);
getGetterSetterProposal(context, resultingCollections);

return resultingCollections;
}
Expand All @@ -55,4 +65,58 @@ protected void addEdits(IDocument document, TextEdit editRoot) throws CoreExcept

resultingCollections.add(proposal);
}

private static void getGetterSetterProposal(IInvocationContext context, List<CUCorrectionProposal> resultingCollections) {
final IType type = getSelectionType(context);
try {
if (!GenerateGetterSetterOperation.supportsGetterSetter(type)) {
return;
}
} catch (JavaModelException e) {
return;
}

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

@Override
protected void addEdits(IDocument document, TextEdit editRoot) throws CoreException {
CompilationUnit astRoot = context.getASTRoot();
GenerateGetterSetterOperation operation = new GenerateGetterSetterOperation(type, astRoot);
TextEdit textEdit = operation.createTextEdit(null);
if (textEdit != null) {
editRoot.addChild(textEdit);
}
}
};

resultingCollections.add(proposal);
}

private static IType getSelectionType(IInvocationContext context) {
ICompilationUnit unit = context.getCompilationUnit();
ASTNode node = context.getCoveredNode();
if (node == null) {
node = context.getCoveringNode();
}

ITypeBinding typeBinding = null;
while (node != null && !(node instanceof CompilationUnit)) {
if (node instanceof TypeDeclaration) {
typeBinding = ((TypeDeclaration) node).resolveBinding();
break;
} else if (node instanceof AnonymousClassDeclaration) { // Anonymous
typeBinding = ((AnonymousClassDeclaration) node).resolveBinding();
break;
}

node = node.getParent();
}

if (typeBinding != null && typeBinding.getJavaElement() instanceof IType) {
return (IType) typeBinding.getJavaElement();
}

return unit.findPrimaryType();
}
}
Loading