/*******************************************************************************
* Copyright (c) 2000, 2011 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.che.ide.ext.java.jdt.internal.text.correction.proposals;
import org.eclipse.che.ide.ext.java.jdt.Images;
import org.eclipse.che.ide.ext.java.jdt.JavaPreferencesSettings;
import org.eclipse.che.ide.ext.java.jdt.core.dom.AST;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ASTNode;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Block;
import org.eclipse.che.ide.ext.java.jdt.core.dom.CompilationUnit;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Expression;
import org.eclipse.che.ide.ext.java.jdt.core.dom.IMethodBinding;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ITypeBinding;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Javadoc;
import org.eclipse.che.ide.ext.java.jdt.core.dom.MethodDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Modifier;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Name;
import org.eclipse.che.ide.ext.java.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.SuperConstructorInvocation;
import org.eclipse.che.ide.ext.java.jdt.core.dom.TypeDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.che.ide.ext.java.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.codemanipulation.StubUtility;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.dom.ASTNodeFactory;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.dom.Bindings;
import org.eclipse.che.ide.ext.java.jdt.internal.text.correction.CorrectionMessages;
import org.eclipse.che.ide.ext.java.worker.WorkerMessageHandler;
import org.eclipse.che.ide.ext.java.jdt.text.Document;
import org.eclipse.che.ide.runtime.CoreException;
import java.util.List;
public class ConstructorFromSuperclassProposal extends LinkedCorrectionProposal {
private TypeDeclaration fTypeNode;
private IMethodBinding fSuperConstructor;
public ConstructorFromSuperclassProposal(TypeDeclaration typeNode, IMethodBinding superConstructor, int relevance,
Document document) {
super("", null, relevance, document, null); //$NON-NLS-1$
fTypeNode = typeNode;
fSuperConstructor = superConstructor;
}
/* (non-Javadoc)
* @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage()
*/
@Override
public Images getImage() {
return Images.publicMethod;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeCorrectionProposal#getName()
*/
@Override
public String getName() {
StringBuffer buf = new StringBuffer();
buf.append(fTypeNode.getName().getIdentifier());
buf.append('(');
if (fSuperConstructor != null) {
ITypeBinding[] paramTypes = fSuperConstructor.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
if (i > 0) {
buf.append(',');
}
buf.append(paramTypes[i].getName());
}
}
buf.append(')');
return CorrectionMessages.INSTANCE.ConstructorFromSuperclassProposal_description(buf.toString());
}
/* (non-Javadoc)
* @see org.eclipse.jdt.internal.ui.text.correction.ASTRewriteCorrectionProposal#getRewrite()
*/
@Override
protected ASTRewrite getRewrite() throws CoreException {
AST ast = fTypeNode.getAST();
ASTRewrite rewrite = ASTRewrite.create(ast);
createImportRewrite((CompilationUnit)fTypeNode.getRoot());
CodeGenerationSettings settings = JavaPreferencesSettings.getCodeGenerationSettings();
if (!settings.createComments) {
settings = null;
}
ImportRewriteContext importRewriteContext =
new ContextSensitiveImportRewriteContext(fTypeNode, getImportRewrite());
MethodDeclaration newMethodDecl =
createNewMethodDeclaration(ast, fSuperConstructor, rewrite, importRewriteContext, settings);
rewrite.getListRewrite(fTypeNode, TypeDeclaration.BODY_DECLARATIONS_PROPERTY).insertFirst(newMethodDecl, null);
addLinkedRanges(rewrite, newMethodDecl);
return rewrite;
}
private void addLinkedRanges(ASTRewrite rewrite, MethodDeclaration newStub) {
List<SingleVariableDeclaration> parameters = newStub.parameters();
for (int i = 0; i < parameters.size(); i++) {
SingleVariableDeclaration curr = parameters.get(i);
String name = curr.getName().getIdentifier();
// addLinkedPosition(rewrite.track(curr.getType()), false, "arg_type_" + name); //$NON-NLS-1$
// addLinkedPosition(rewrite.track(curr.getName()), false, "arg_name_" + name); //$NON-NLS-1$
}
}
private MethodDeclaration createNewMethodDeclaration(AST ast, IMethodBinding binding, ASTRewrite rewrite,
ImportRewriteContext importRewriteContext, CodeGenerationSettings commentSettings)
throws CoreException {
String name = fTypeNode.getName().getIdentifier();
MethodDeclaration decl = ast.newMethodDeclaration();
decl.setConstructor(true);
decl.setName(ast.newSimpleName(name));
Block body = ast.newBlock();
decl.setBody(body);
SuperConstructorInvocation invocation = null;
List<SingleVariableDeclaration> parameters = decl.parameters();
String[] paramNames = getArgumentNames(binding);
ITypeBinding enclosingInstance = getEnclosingInstance();
if (enclosingInstance != null) {
invocation =
addEnclosingInstanceAccess(rewrite, importRewriteContext, parameters, paramNames, enclosingInstance);
}
if (binding == null) {
decl.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
} else {
decl.modifiers().addAll(ASTNodeFactory.newModifiers(ast, binding.getModifiers()));
ITypeBinding[] params = binding.getParameterTypes();
for (int i = 0; i < params.length; i++) {
SingleVariableDeclaration var = ast.newSingleVariableDeclaration();
var.setType(getImportRewrite().addImport(params[i], ast, importRewriteContext));
var.setName(ast.newSimpleName(paramNames[i]));
parameters.add(var);
}
List<Name> thrownExceptions = decl.thrownExceptions();
ITypeBinding[] excTypes = binding.getExceptionTypes();
for (int i = 0; i < excTypes.length; i++) {
String excTypeName = getImportRewrite().addImport(excTypes[i], importRewriteContext);
thrownExceptions.add(ASTNodeFactory.newName(ast, excTypeName));
}
if (invocation == null) {
invocation = ast.newSuperConstructorInvocation();
}
List<Expression> arguments = invocation.arguments();
for (int i = 0; i < paramNames.length; i++) {
Name argument = ast.newSimpleName(paramNames[i]);
arguments.add(argument);
// addLinkedPosition(rewrite.track(argument), false, "arg_name_" + paramNames[i]); //$NON-NLS-1$
}
}
String bodyStatement =
(invocation == null)
? "" : ASTNodes.asFormattedString(invocation, 0, String.valueOf('\n'), WorkerMessageHandler.get().getOptions()); //$NON-NLS-1$
String placeHolder = StubUtility.getMethodBodyContent(true, name, name, bodyStatement, String.valueOf('\n'));
// CodeGeneration.getMethodBodyContent(name, name, true, bodyStatement,
// String.valueOf('\n'));
if (placeHolder != null) {
ASTNode todoNode = rewrite.createStringPlaceholder(placeHolder, ASTNode.RETURN_STATEMENT);
body.statements().add(todoNode);
}
if (commentSettings != null) {
String string = getMethodComment(name, decl, binding, "\n");
if (string != null) {
Javadoc javadoc = (Javadoc)rewrite.createStringPlaceholder(string, ASTNode.JAVADOC);
decl.setJavadoc(javadoc);
}
}
return decl;
}
private SuperConstructorInvocation addEnclosingInstanceAccess(ASTRewrite rewrite,
ImportRewriteContext importRewriteContext,
List<SingleVariableDeclaration> parameters, String[] paramNames,
ITypeBinding enclosingInstance) {
AST ast = rewrite.getAST();
SuperConstructorInvocation invocation = ast.newSuperConstructorInvocation();
SingleVariableDeclaration var = ast.newSingleVariableDeclaration();
var.setType(getImportRewrite().addImport(enclosingInstance, ast, importRewriteContext));
String[] enclosingArgNames =
StubUtility.getArgumentNameSuggestions(enclosingInstance.getTypeDeclaration().getName(), 0, paramNames);
String firstName = enclosingArgNames[0];
var.setName(ast.newSimpleName(firstName));
parameters.add(var);
Name enclosing = ast.newSimpleName(firstName);
invocation.setExpression(enclosing);
String key = "arg_name_" + firstName; //$NON-NLS-1$
// addLinkedPosition(rewrite.track(enclosing), false, key);
// for (int i = 0; i < enclosingArgNames.length; i++)
// {
// addLinkedPositionProposal(key, enclosingArgNames[i], null); // alternative names
// }
return invocation;
}
private ITypeBinding getEnclosingInstance() {
ITypeBinding currBinding = fTypeNode.resolveBinding();
if (currBinding == null || Modifier.isStatic(currBinding.getModifiers())) {
return null;
}
ITypeBinding superBinding = currBinding.getSuperclass();
if (superBinding == null || superBinding.getDeclaringClass() == null
|| Modifier.isStatic(superBinding.getModifiers())) {
return null;
}
ITypeBinding enclosing = superBinding.getDeclaringClass();
while (currBinding != null) {
if (Bindings.isSuperType(enclosing, currBinding)) {
return null; // enclosing in scope
}
if (Modifier.isStatic(currBinding.getModifiers())) {
return null; // no more enclosing instances
}
currBinding = currBinding.getDeclaringClass();
}
return enclosing;
}
private String[] getArgumentNames(IMethodBinding binding) {
if (binding == null) {
return new String[0];
}
return StubUtility.suggestArgumentNames(binding);
}
}