blob: f9e7a2ce7d6d129f98e58097e7f0ea0f9bb34a15 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 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
* Stephan Herrmann - Contribution for Bug 463360 - [override method][null] generating method override should not create redundant null annotations
*******************************************************************************/
package org.eclipse.jdt.internal.ui.text.java;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.jface.viewers.StyledString;
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.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
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.NodeFinder;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jdt.core.formatter.IndentManipulation;
import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2;
import org.eclipse.jdt.internal.corext.dom.Bindings;
import org.eclipse.jdt.ui.SharedASTProvider;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
public class OverrideCompletionProposal extends JavaTypeCompletionProposal implements ICompletionProposalExtension4 {
private IJavaProject fJavaProject;
private String fMethodName;
private String[] fParamTypes;
public OverrideCompletionProposal(IJavaProject jproject, ICompilationUnit cu, String methodName, String[] paramTypes, int start, int length, StyledString displayName, String completionProposal) {
super(completionProposal, cu, start, length, null, displayName, 0);
Assert.isNotNull(jproject);
Assert.isNotNull(methodName);
Assert.isNotNull(paramTypes);
Assert.isNotNull(cu);
fParamTypes= paramTypes;
fMethodName= methodName;
fJavaProject= jproject;
StringBuffer buffer= new StringBuffer();
buffer.append(completionProposal);
buffer.append(" {};"); //$NON-NLS-1$
setReplacementString(buffer.toString());
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension3#getPrefixCompletionText(org.eclipse.jface.text.IDocument,int)
*/
@Override
public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
return fMethodName;
}
private CompilationUnit getRecoveredAST(IDocument document, int offset, Document recoveredDocument) {
CompilationUnit ast= SharedASTProvider.getAST(fCompilationUnit, SharedASTProvider.WAIT_ACTIVE_ONLY, null);
if (ast != null) {
recoveredDocument.set(document.get());
return ast;
}
char[] content= document.get().toCharArray();
// clear prefix to avoid compile errors
int index= offset - 1;
while (index >= 0 && Character.isJavaIdentifierPart(content[index])) {
content[index]= ' ';
index--;
}
recoveredDocument.set(new String(content));
final ASTParser parser= ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL);
parser.setResolveBindings(true);
parser.setStatementsRecovery(true);
parser.setSource(content);
parser.setUnitName(fCompilationUnit.getElementName());
parser.setProject(fCompilationUnit.getJavaProject());
return (CompilationUnit) parser.createAST(new NullProgressMonitor());
}
/*
* @see JavaTypeCompletionProposal#updateReplacementString(IDocument,char,int,ImportRewrite)
*/
@Override
protected boolean updateReplacementString(IDocument document, char trigger, int offset, ImportRewrite importRewrite) throws CoreException, BadLocationException {
Document recoveredDocument= new Document();
CompilationUnit unit= getRecoveredAST(document, offset, recoveredDocument);
ImportRewriteContext context;
if (importRewrite != null) {
context= new ContextSensitiveImportRewriteContext(unit, offset, importRewrite);
} else {
importRewrite= StubUtility.createImportRewrite(unit, true); // create a dummy import rewriter to have one
context= new ImportRewriteContext() { // forces that all imports are fully qualified
@Override
public int findInContext(String qualifier, String name, int kind) {
return RES_NAME_CONFLICT;
}
};
}
ITypeBinding declaringType= null;
ChildListPropertyDescriptor descriptor= null;
ASTNode node= NodeFinder.perform(unit, offset, 1);
if (node instanceof AnonymousClassDeclaration) {
declaringType= ((AnonymousClassDeclaration) node).resolveBinding();
descriptor= AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY;
} else if (node instanceof AbstractTypeDeclaration) {
AbstractTypeDeclaration declaration= (AbstractTypeDeclaration) node;
descriptor= declaration.getBodyDeclarationsProperty();
declaringType= declaration.resolveBinding();
}
if (declaringType != null) {
ASTRewrite rewrite= ASTRewrite.create(unit.getAST());
IMethodBinding methodToOverride= Bindings.findMethodInHierarchy(declaringType, fMethodName, fParamTypes);
if (methodToOverride == null && declaringType.isInterface()) {
methodToOverride= Bindings.findMethodInType(node.getAST().resolveWellKnownType("java.lang.Object"), fMethodName, fParamTypes); //$NON-NLS-1$
}
if (methodToOverride != null) {
CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(fJavaProject);
MethodDeclaration stub= StubUtility2.createImplementationStub(fCompilationUnit, rewrite, importRewrite, context, methodToOverride, declaringType, settings, declaringType.isInterface(), declaringType);
ListRewrite rewriter= rewrite.getListRewrite(node, descriptor);
rewriter.insertFirst(stub, null);
ITrackedNodePosition position= rewrite.track(stub);
try {
rewrite.rewriteAST(recoveredDocument, fJavaProject.getOptions(true)).apply(recoveredDocument);
String generatedCode= recoveredDocument.get(position.getStartPosition(), position.getLength());
int generatedIndent= IndentManipulation.measureIndentUnits(getIndentAt(recoveredDocument, position.getStartPosition(), settings), settings.tabWidth, settings.indentWidth);
String indent= getIndentAt(document, getReplacementOffset(), settings);
setReplacementString(IndentManipulation.changeIndent(generatedCode, generatedIndent, settings.tabWidth, settings.indentWidth, indent, TextUtilities.getDefaultLineDelimiter(document)));
} catch (MalformedTreeException exception) {
JavaPlugin.log(exception);
} catch (BadLocationException exception) {
JavaPlugin.log(exception);
}
}
}
return true;
}
private static String getIndentAt(IDocument document, int offset, CodeGenerationSettings settings) {
try {
IRegion region= document.getLineInformationOfOffset(offset);
return IndentManipulation.extractIndentString(document.get(region.getOffset(), region.getLength()), settings.tabWidth, settings.indentWidth);
} catch (BadLocationException e) {
return ""; //$NON-NLS-1$
}
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension4#isAutoInsertable()
*/
@Override
public boolean isAutoInsertable() {
return false;
}
}