blob: f9bf9b01e5f0454ef88660dcaa034a8f2f6aafaf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 IBM 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.corext.codemanipulation;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.dom.AST;
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.ChildListPropertyDescriptor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
/**
* Workspace runnable to add unimplemented constructors.
*
* @since 3.1
*/
public final class AddUnimplementedConstructorsOperation implements IWorkspaceRunnable {
/** Should the resulting edit be applied? */
private final boolean fApply;
/** The qualified names of the generated imports */
private String[] fCreatedImports;
/** The method binding keys for which a constructor was generated */
private final List fCreatedMethods= new ArrayList();
/** Should the import edits be applied? */
private final boolean fImports;
/** The insertion point, or <code>-1</code> */
private final int fInsertPos;
/** The method bindings to implement */
private final IMethodBinding[] fConstructorsToImplement;
/** Should the call to the super constructor be omitted? */
private boolean fOmitSuper;
/** Should the compilation unit content be saved? */
private final boolean fSave;
/** Specified if comments should be created */
private boolean fCreateComments;
/** The type declaration to add the constructors to */
private final ITypeBinding fType;
/** The compilation unit AST node */
private final CompilationUnit fASTRoot;
/** The visibility flags of the new constructor */
private int fVisibility;
/**
* Creates a new add unimplemented constructors operation.
*
* @param astRoot the compilation unit AST node
* @param type the type to add the methods to
* @param constructorsToImplement the method binding keys to implement
* @param insertPos the insertion point, or <code>-1</code>
* @param imports <code>true</code> if the import edits should be applied, <code>false</code> otherwise
* @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 AddUnimplementedConstructorsOperation(CompilationUnit astRoot, ITypeBinding type, IMethodBinding[] constructorsToImplement, int insertPos, final boolean imports, final boolean apply, final boolean save) {
if (astRoot == null || !(astRoot.getJavaElement() instanceof ICompilationUnit)) {
throw new IllegalArgumentException("AST must not be null and has to be created from a ICompilationUnit"); //$NON-NLS-1$
}
if (type == null) {
throw new IllegalArgumentException("The type must not be null"); //$NON-NLS-1$
}
ASTNode node= astRoot.findDeclaringNode(type);
if (!(node instanceof AnonymousClassDeclaration || node instanceof AbstractTypeDeclaration)) {
throw new IllegalArgumentException("type has to map to a type declaration in the AST"); //$NON-NLS-1$
}
fType= type;
fInsertPos= insertPos;
fASTRoot= astRoot;
fConstructorsToImplement= constructorsToImplement;
fSave= save;
fApply= apply;
fImports= imports;
fCreateComments= StubUtility.doAddComments(astRoot.getJavaElement().getJavaProject());
fVisibility= Modifier.PUBLIC;
fOmitSuper= false;
}
/**
* Returns the method binding keys for which a constructor has been generated.
*
* @return the method binding keys
*/
public String[] getCreatedConstructors() {
final String[] keys= new String[fCreatedMethods.size()];
fCreatedMethods.toArray(keys);
return keys;
}
/**
* Returns the qualified names of the generated imports.
*
* @return the generated imports
*/
public String[] getCreatedImports() {
return fCreatedImports;
}
/**
* Returns the scheduling rule for this operation.
*
* @return the scheduling rule
*/
public ISchedulingRule getSchedulingRule() {
return ResourcesPlugin.getWorkspace().getRoot();
}
/**
* Returns the visibility of the constructors.
*
* @return the visibility
*/
public int getVisibility() {
return fVisibility;
}
/**
* Returns whether the super call should be omitted.
*
* @return <code>true</code> to omit the super call, <code>false</code> otherwise
*/
public boolean isOmitSuper() {
return fOmitSuper;
}
/**
* Determines whether to create comments.
* @param comments <code>true</code> to create comments, <code>false</code> otherwise
*/
public void setCreateComments(final boolean comments) {
fCreateComments= comments;
}
/*
* @see org.eclipse.core.resources.IWorkspaceRunnable#run(org.eclipse.core.runtime.IProgressMonitor)
*/
public void run(IProgressMonitor monitor) throws CoreException {
if (monitor == null)
monitor= new NullProgressMonitor();
try {
monitor.beginTask("", 2); //$NON-NLS-1$
monitor.setTaskName(CodeGenerationMessages.AddUnimplementedMethodsOperation_description);
fCreatedMethods.clear();
ICompilationUnit cu= (ICompilationUnit) fASTRoot.getJavaElement();
AST ast= fASTRoot.getAST();
ASTRewrite astRewrite= ASTRewrite.create(ast);
ImportRewrite importRewrite= StubUtility.createImportRewrite(fASTRoot, true);
ITypeBinding currTypeBinding= fType;
ListRewrite memberRewriter= null;
ASTNode node= fASTRoot.findDeclaringNode(currTypeBinding);
if (node instanceof AnonymousClassDeclaration) {
memberRewriter= astRewrite.getListRewrite(node, AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY);
} else if (node instanceof AbstractTypeDeclaration) {
ChildListPropertyDescriptor property= ((AbstractTypeDeclaration) node).getBodyDeclarationsProperty();
memberRewriter= astRewrite.getListRewrite(node, property);
} else {
throw new IllegalArgumentException();
// not possible, we checked this in the constructor
}
final CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu.getJavaProject());
settings.createComments= fCreateComments;
ASTNode insertion= getNodeToInsertBefore(memberRewriter);
IMethodBinding[] toImplement= fConstructorsToImplement;
if (toImplement == null) {
toImplement= StubUtility2.getVisibleConstructors(currTypeBinding, true, true);
}
int deprecationCount= 0;
for (int i= 0; i < toImplement.length; i++) {
if (toImplement[i].isDeprecated())
deprecationCount++;
}
boolean createDeprecated= deprecationCount == toImplement.length;
for (int i= 0; i < toImplement.length; i++) {
IMethodBinding curr= toImplement[i];
if (!curr.isDeprecated() || createDeprecated) {
MethodDeclaration stub= StubUtility2.createConstructorStub(cu, astRewrite, importRewrite, curr, currTypeBinding.getName(), fVisibility, fOmitSuper, true, settings);
if (stub != null) {
fCreatedMethods.add(curr.getKey());
if (insertion != null)
memberRewriter.insertBefore(stub, insertion, null);
else
memberRewriter.insertLast(stub, null);
}
}
}
MultiTextEdit edit= new MultiTextEdit();
TextEdit importEdits= importRewrite.rewriteImports(new SubProgressMonitor(monitor, 1));
fCreatedImports= importRewrite.getCreatedImports();
if (fImports) {
edit.addChild(importEdits);
}
edit.addChild(astRewrite.rewriteAST());
if (fApply) {
JavaModelUtil.applyEdit(cu, edit, fSave, new SubProgressMonitor(monitor, 1));
}
} finally {
monitor.done();
}
}
/**
* Determines whether the super call should be omitted.
*
* @param omit <code>true</code> to omit the super call, <code>false</code> otherwise
*/
public void setOmitSuper(final boolean omit) {
fOmitSuper= omit;
}
/**
* Determines the visibility of the constructors.
*
* @param visibility the visibility
*/
public void setVisibility(final int visibility) {
fVisibility= visibility;
}
private ASTNode getNodeToInsertBefore(ListRewrite rewriter) {
if (fInsertPos != -1) {
List members= rewriter.getOriginalList();
for (int i= 0; i < members.size(); i++) {
ASTNode curr= (ASTNode) members.get(i);
if (curr.getStartPosition() >= fInsertPos) {
return curr;
}
}
}
return null;
}
}