/******************************************************************************* * Copyright (c) 2017 Rogue Wave Software 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: * Rogue Wave Software Inc. - initial implementation *******************************************************************************/ package org.eclipse.php.internal.ui.actions; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.dltk.ast.Modifiers; import org.eclipse.dltk.core.*; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.php.core.ast.nodes.*; import org.eclipse.php.internal.core.ast.rewrite.ASTRewrite; import org.eclipse.php.internal.core.ast.rewrite.ListRewrite; import org.eclipse.php.internal.core.corext.dom.NodeFinder; import org.eclipse.php.internal.ui.PHPUiPlugin; import org.eclipse.php.ui.util.CodeGenerationUtils; import org.eclipse.text.edits.MalformedTreeException; import org.eclipse.text.edits.TextEdit; /** * Workspace runnable to add accessor methods to fields. * */ public final class AddGetterSetterOperation implements IWorkspaceRunnable { /** The accessor fields */ private final IField[] fAccessorFields; /** Should the resulting edit be applied? */ private boolean fApply = true; /** The resulting text edit */ private TextEdit fEdit = null; /** The getter fields */ private final IField[] fGetterFields; /** The insertion point, or <code>null</code> */ private final IMethod fInsert; /** The setter fields */ private final IField[] fSetterFields; /** The code generation settings to use */ private final CodeGenerationSettings fSettings; /** Should all existing members be skipped? */ private boolean fSkipAllExisting = false; /** Should the accessors be sorted? */ private boolean fSort = false; /** The type declaration to add the constructors to */ private final IType fType; /** The compilation unit ast node */ private final Program fASTRoot; /** The visibility flags of the new accessors */ private int fVisibility = Modifiers.AccPublic; private IDocument fDocument; /** * Creates a new add getter setter operation. * * @param type * the type to add the accessors to * @param getters * the fields to create getters for * @param setters * the fields to create setters for * @param accessors * the fields to create both * @param unit * the compilation unit ast node * @param skipExistingQuery * the request query * @param insert * the insertion point, or <code>null</code> * @param settings * the code generation settings to use * @param apply * <code>true</code> if the resulting edit should be applied, * <code>false</code> otherwise * @param save * <code>true</code> if the changed compilation unit should be * saved, <code>false</code> otherwise */ public AddGetterSetterOperation(final IType type, final IField[] getters, final IField[] setters, final IField[] accessors, final Program unit, final IDocument document, final IMethod insert, final CodeGenerationSettings settings, final boolean apply) { Assert.isNotNull(type); Assert.isNotNull(unit); Assert.isNotNull(settings); fType = type; fGetterFields = getters; fSetterFields = setters; fAccessorFields = accessors; fASTRoot = unit; fInsert = insert; fSettings = settings; fApply = apply; fDocument = document; } /** * Generates a new getter method for the specified field * * @param field * the field * @param rewrite * the list rewrite to use * @throws CoreException * if an error occurs * @throws OperationCanceledException * if the operation has been cancelled */ private void generateGetterMethod(final IField field, final ListRewrite rewrite) throws CoreException { final IType type = field.getDeclaringType(); final String name = CodeGenerationUtils.getGetterName(field); final IMethod existing = CodeGenerationUtils.findMethod(name, 0, false, type); if (existing == null) { IModelElement sibling = fInsert; ASTNode insertion = CodeGenerationUtils.getNodeToInsertBefore(rewrite, sibling); CodeGenerationUtils.createGetterStub(field, name, fSettings.createComments, fVisibility | (field.getFlags() & Flags.AccStatic), type, rewrite, insertion); } } /** * Generates a new setter method for the specified field * * @param field * the field * @param astRewrite * @param rewrite * the list rewrite to use * @throws CoreException * if an error occurs * @throws OperationCanceledException * if the operation has been cancelled */ private void generateSetterMethod(final IField field, ASTRewrite astRewrite, final ListRewrite rewrite) throws CoreException { final IType type = field.getDeclaringType(); final String name = CodeGenerationUtils.getSetterName(field); final IMethod existing = CodeGenerationUtils.findMethod(name, 1, false, type); if (existing == null) { IModelElement sibling = fInsert; ASTNode insertion = CodeGenerationUtils.getNodeToInsertBefore(rewrite, sibling); CodeGenerationUtils.createSetterStub(field, name, fSettings.createComments, fVisibility | (field.getFlags() & Flags.AccStatic), rewrite, insertion); } } /** * Returns the resulting text edit. * * @return the resulting text edit */ public final TextEdit getResultingEdit() { return fEdit; } /** * Returns the scheduling rule for this operation. * * @return the scheduling rule */ public final ISchedulingRule getSchedulingRule() { return ResourcesPlugin.getWorkspace().getRoot(); } /** * Returns the visibility modifier of the generated constructors. * * @return the visibility modifier */ public final int getVisibility() { return fVisibility; } /** * Should all existing members be skipped? * * @return <code>true</code> if they should be skipped, <code>false</code> * otherwise */ public final boolean isSkipAllExisting() { return fSkipAllExisting; } @Override public final void run(IProgressMonitor monitor) throws CoreException { if (monitor == null) { monitor = new NullProgressMonitor(); } monitor.setTaskName("AddGetterSetterOperation_description"); //$NON-NLS-1$ monitor.beginTask("", fGetterFields.length + fSetterFields.length); //$NON-NLS-1$ final ASTRewrite astRewrite = ASTRewrite.create(fASTRoot.getAST()); ListRewrite listRewriter = null; final ClassDeclaration declaration = (ClassDeclaration) ASTNodes.getParent( NodeFinder.perform(fASTRoot, fType.getNameRange().getOffset(), fType.getNameRange().getLength()), ClassDeclaration.class); if (declaration != null) { listRewriter = astRewrite.getListRewrite(declaration.getBody(), Block.STATEMENTS_PROPERTY); } if (listRewriter == null) { throw new CoreException( new Status(IStatus.ERROR, PHPUiPlugin.ID, IStatus.ERROR, "error_input_type_not_found", null)); //$NON-NLS-1$ } if (!fSort) { for (IField accessorField : fAccessorFields) { generateGetterMethod(accessorField, listRewriter); generateSetterMethod(accessorField, astRewrite, listRewriter); monitor.worked(1); if (monitor.isCanceled()) { throw new OperationCanceledException(); } } } for (IField getterField : fGetterFields) { generateGetterMethod(getterField, listRewriter); monitor.worked(1); if (monitor.isCanceled()) { throw new OperationCanceledException(); } } for (IField setterField : fSetterFields) { generateSetterMethod(setterField, astRewrite, listRewriter); monitor.worked(1); if (monitor.isCanceled()) { throw new OperationCanceledException(); } } fEdit = astRewrite.rewriteAST(fDocument, null); if (fApply) { try { fEdit.apply(fDocument); } catch (MalformedTreeException | BadLocationException e) { throw new CoreException( new Status(IStatus.ERROR, PHPUiPlugin.ID, IStatus.ERROR, "error file content", null)); //$NON-NLS-1$ } } monitor.done(); } /** * Determines whether existing members should be skipped. * * @param skip * <code>true</code> to skip existing members, <code>false</code> * otherwise */ public final void setSkipAllExisting(final boolean skip) { fSkipAllExisting = skip; } public void setSort(boolean sort) { fSort = sort; } /** * Sets the visibility modifier of the generated constructors. * * @param visibility * the visibility modifier */ public final void setVisibility(final int visibility) { fVisibility = visibility; } }