blob: cfad0b64f1433ce86765d0bb838ade8c8069a70d [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.ui.text.java;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.text.Assert;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension4;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IBinding;
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.core.formatter.CodeFormatter;
import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.dom.NodeFinder;
import org.eclipse.jdt.internal.corext.template.java.SignatureUtil;
import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.Strings;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jdt.internal.ui.dialogs.OverrideMethodDialog;
import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
public class AnonymousTypeCompletionProposal extends JavaTypeCompletionProposal implements ICompletionProposalExtension4 {
private String fDeclarationSignature;
private IType fSuperType;
public AnonymousTypeCompletionProposal(IJavaProject jproject, ICompilationUnit cu, int start, int length, String constructorCompletion, String displayName, String declarationSignature, int relevance) {
super(constructorCompletion, cu, start, length, null, displayName, relevance);
Assert.isNotNull(declarationSignature);
Assert.isNotNull(jproject);
Assert.isNotNull(cu);
fDeclarationSignature= declarationSignature;
fSuperType= getDeclaringType(jproject, SignatureUtil.stripSignatureToFQN(String.valueOf(declarationSignature)));
setImage(getImageForType(fSuperType));
setCursorPosition(constructorCompletion.indexOf('(') + 1);
}
private int createDummy(String name, StringBuffer buffer) throws JavaModelException {
String lineDelim= "\n"; // Using newline is ok since source is used in dummy compilation unit //$NON-NLS-1$
buffer.append("class "); //$NON-NLS-1$
buffer.append(name);
if (fSuperType.isInterface())
buffer.append(" implements "); //$NON-NLS-1$
else
buffer.append(" extends "); //$NON-NLS-1$
if (fDeclarationSignature != null)
buffer.append(Signature.toString(fDeclarationSignature));
else
buffer.append(fSuperType.getFullyQualifiedParameterizedName());
int start= buffer.length();
buffer.append("{"); //$NON-NLS-1$
buffer.append(lineDelim);
buffer.append(lineDelim);
buffer.append("}"); //$NON-NLS-1$
return start;
}
private boolean createStubs(StringBuffer buffer, ImportRewrite importRewrite) throws CoreException {
if (importRewrite == null)
return false;
if (fSuperType == null)
return true;
ICompilationUnit copy= null;
try {
final String name= "Type" + System.currentTimeMillis(); //$NON-NLS-1$
copy= fCompilationUnit.getPrimary().getWorkingCopy(null);
final StringBuffer contents= new StringBuffer();
int start= 0;
int end= 0;
ISourceRange range= fSuperType.getSourceRange();
final boolean sameUnit= range != null && fCompilationUnit.equals(fSuperType.getCompilationUnit());
final StringBuffer dummy= new StringBuffer();
final int length= createDummy(name, dummy);
contents.append(fCompilationUnit.getBuffer().getContents());
if (sameUnit) {
final int size= range.getOffset() + range.getLength();
start= size + length;
end= contents.length() - size;
contents.insert(size, dummy.toString());
} else {
range= fCompilationUnit.getTypes()[0].getSourceRange();
start= range.getOffset() + length;
end= contents.length() - range.getOffset();
contents.insert(range.getOffset(), dummy.toString());
}
copy.getBuffer().setContents(contents.toString());
JavaModelUtil.reconcile(copy);
final ASTParser parser= ASTParser.newParser(AST.JLS3);
parser.setResolveBindings(true);
parser.setSource(copy);
final CompilationUnit unit= (CompilationUnit) parser.createAST(new NullProgressMonitor());
IType type= null;
IType[] types= copy.getAllTypes();
for (int index= 0; index < types.length; index++) {
IType result= types[index];
if (result.getElementName().equals(name)) {
type= result;
break;
}
}
if (type != null && type.exists()) {
ITypeBinding binding= null;
final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration) ASTNodes.getParent(NodeFinder.perform(unit, type.getNameRange()), AbstractTypeDeclaration.class);
if (declaration != null) {
binding= declaration.resolveBinding();
if (binding != null) {
IMethodBinding[] bindings= StubUtility2.getOverridableMethods(unit.getAST(), binding, true);
CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(fSuperType.getJavaProject());
String[] keys= null;
if (!fSuperType.isInterface() && !fSuperType.isAnnotation()) {
OverrideMethodDialog dialog= new OverrideMethodDialog(JavaPlugin.getActiveWorkbenchShell(), null, type, true);
dialog.setGenerateComment(false);
dialog.setElementPositionEnabled(false);
if (dialog.open() == Window.OK) {
Object[] selection= dialog.getResult();
if (selection != null) {
ArrayList result= new ArrayList(selection.length);
for (int index= 0; index < selection.length; index++) {
if (selection[index] instanceof IMethodBinding)
result.add(((IBinding) selection[index]).getKey());
}
keys= (String[]) result.toArray(new String[result.size()]);
settings.createComments= dialog.getGenerateComment();
}
}
} else {
settings.createComments= false;
List list= new ArrayList();
for (int index= 0; index < bindings.length; index++) {
if (Modifier.isAbstract(bindings[index].getModifiers()))
list.add(bindings[index].getKey());
}
keys= (String[]) list.toArray(new String[list.size()]);
}
if (keys == null) {
setReplacementString(""); //$NON-NLS-1$
setReplacementLength(0);
return false;
}
ASTRewrite rewrite= ASTRewrite.create(unit.getAST());
ListRewrite rewriter= rewrite.getListRewrite(declaration, declaration.getBodyDeclarationsProperty());
String key= null;
MethodDeclaration stub= null;
for (int index= 0; index < keys.length; index++) {
key= keys[index];
for (int offset= 0; offset < bindings.length; offset++) {
if (key.equals(bindings[offset].getKey())) {
stub= StubUtility2.createImplementationStub(copy, rewrite, importRewrite, bindings[offset], binding.getName(), binding.isInterface(), settings);
if (stub != null)
rewriter.insertFirst(stub, null);
break;
}
}
}
IDocument document= new Document(copy.getBuffer().getContents());
try {
rewrite.rewriteAST(document, fCompilationUnit.getJavaProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
buffer.append(document.get(start, document.getLength() - start - end));
} catch (MalformedTreeException exception) {
JavaPlugin.log(exception);
} catch (BadLocationException exception) {
JavaPlugin.log(exception);
}
}
}
}
return true;
} finally {
if (copy != null)
copy.discardWorkingCopy();
}
}
private IType getDeclaringType(IJavaProject project, String typeName) {
try {
return JavaModelUtil.findType(project, typeName);
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
return null;
}
private Image getImageForType(IType type) {
String imageName= JavaPluginImages.IMG_OBJS_CLASS; // default
if (type != null) {
try {
if (type.isAnnotation()) {
imageName= JavaPluginImages.IMG_OBJS_ANNOTATION;
} else if (type.isInterface()) {
imageName= JavaPluginImages.IMG_OBJS_INTERFACE;
}
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
}
return JavaPluginImages.get(imageName);
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension4#isAutoInsertable()
*/
public boolean isAutoInsertable() {
return false;
}
protected boolean updateReplacementString(IDocument document, char trigger, int offset, ImportRewrite impRewrite) throws CoreException, BadLocationException {
String replacementString= getReplacementString();
// construct replacement text: an expression to be formatted
StringBuffer buf= new StringBuffer("new A("); //$NON-NLS-1$
buf.append(replacementString);
if (!replacementString.endsWith(")")) { //$NON-NLS-1$
buf.append(')');
}
if (!createStubs(buf, impRewrite)) {
return false;
}
if (document.getChar(offset) != ')')
buf.append(';');
// use the code formatter
String lineDelim= TextUtilities.getDefaultLineDelimiter(document);
final IJavaProject project= fCompilationUnit.getJavaProject();
IRegion region= document.getLineInformationOfOffset(getReplacementOffset());
int indent= Strings.computeIndentUnits(document.get(region.getOffset(), region.getLength()), project);
String replacement= CodeFormatterUtil.format(CodeFormatter.K_EXPRESSION, buf.toString(), 0, null, lineDelim, project);
replacement= Strings.changeIndent(replacement, 0, project, CodeFormatterUtil.createIndentString(indent, project), lineDelim);
setReplacementString(replacement.substring(replacement.indexOf('(') + 1));
int pos= offset;
while (pos < document.getLength() && Character.isWhitespace(document.getChar(pos))) {
pos++;
}
if (pos < document.getLength() && document.getChar(pos) == ')') {
setReplacementLength(pos - offset + 1);
}
return true;
}
}