/*******************************************************************************
* 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;
import org.eclipse.che.ide.ext.java.jdt.Images;
import org.eclipse.che.ide.ext.java.jdt.codeassistant.api.IProblemLocation;
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.ASTVisitor;
import org.eclipse.che.ide.ext.java.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.AnnotationTypeDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Block;
import org.eclipse.che.ide.ext.java.jdt.core.dom.BodyDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.CompilationUnit;
import org.eclipse.che.ide.ext.java.jdt.core.dom.EnumDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Expression;
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.PrimitiveType;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ReturnStatement;
import org.eclipse.che.ide.ext.java.jdt.core.dom.TagElement;
import org.eclipse.che.ide.ext.java.jdt.core.dom.TextElement;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Type;
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;
import org.eclipse.che.ide.ext.java.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.codemanipulation.ASTResolving;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
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.proposals.ASTRewriteCorrectionProposal;
import org.eclipse.che.ide.ext.java.jdt.internal.text.correction.proposals.LinkedCorrectionProposal;
import org.eclipse.che.ide.ext.java.jdt.internal.text.correction.proposals.MissingReturnTypeCorrectionProposal;
import org.eclipse.che.ide.ext.java.jdt.internal.text.correction.proposals.ReplaceCorrectionProposal;
import org.eclipse.che.ide.ext.java.jdt.internal.ui.BindingLabelProvider;
import org.eclipse.che.ide.ext.java.jdt.quickassist.api.InvocationContext;
import java.util.ArrayList;
import java.util.Collection;
public class ReturnTypeSubProcessor {
private static class ReturnStatementCollector extends ASTVisitor {
private ArrayList<ReturnStatement> fResult = new ArrayList<ReturnStatement>();
public ITypeBinding getTypeBinding(AST ast) {
boolean couldBeObject = false;
for (int i = 0; i < fResult.size(); i++) {
ReturnStatement node = fResult.get(i);
Expression expr = node.getExpression();
if (expr != null) {
ITypeBinding binding = Bindings.normalizeTypeBinding(expr.resolveTypeBinding());
if (binding != null) {
return binding;
} else {
couldBeObject = true;
}
} else {
return ast.resolveWellKnownType("void"); //$NON-NLS-1$
}
}
if (couldBeObject) {
return ast.resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
}
return ast.resolveWellKnownType("void"); //$NON-NLS-1$
}
@Override
public boolean visit(ReturnStatement node) {
fResult.add(node);
return false;
}
@Override
public boolean visit(AnonymousClassDeclaration node) {
return false;
}
@Override
public boolean visit(TypeDeclaration node) {
return false;
}
@Override
public boolean visit(EnumDeclaration node) {
return false;
}
@Override
public boolean visit(AnnotationTypeDeclaration node) {
return false;
}
}
public static void addMethodWithConstrNameProposals(InvocationContext context, IProblemLocation problem,
Collection<ICommandAccess> proposals) {
// ICompilationUnit cu= context.getCompilationUnit();
ASTNode selectedNode = problem.getCoveringNode(context.getASTRoot());
if (selectedNode instanceof MethodDeclaration) {
MethodDeclaration declaration = (MethodDeclaration)selectedNode;
ASTRewrite rewrite = ASTRewrite.create(declaration.getAST());
rewrite.set(declaration, MethodDeclaration.CONSTRUCTOR_PROPERTY, Boolean.TRUE, null);
String label = CorrectionMessages.INSTANCE.ReturnTypeSubProcessor_constrnamemethod_description();
Images image = Images.correction_change;
ASTRewriteCorrectionProposal proposal =
new ASTRewriteCorrectionProposal(label, rewrite, 5, context.getDocument(), image);
proposals.add(proposal);
}
}
public static void addVoidMethodReturnsProposals(InvocationContext context, IProblemLocation problem,
Collection<ICommandAccess> proposals) {
CompilationUnit astRoot = context.getASTRoot();
ASTNode selectedNode = problem.getCoveringNode(astRoot);
if (selectedNode == null) {
return;
}
BodyDeclaration decl = ASTResolving.findParentBodyDeclaration(selectedNode);
if (decl instanceof MethodDeclaration && selectedNode.getNodeType() == ASTNode.RETURN_STATEMENT) {
ReturnStatement returnStatement = (ReturnStatement)selectedNode;
Expression expr = returnStatement.getExpression();
if (expr != null) {
AST ast = astRoot.getAST();
ITypeBinding binding = Bindings.normalizeTypeBinding(expr.resolveTypeBinding());
if (binding == null) {
binding = ast.resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
}
if (binding.isWildcardType()) {
binding = ASTResolving.normalizeWildcardType(binding, true, ast);
}
MethodDeclaration methodDeclaration = (MethodDeclaration)decl;
ASTRewrite rewrite = ASTRewrite.create(ast);
String label =
CorrectionMessages.INSTANCE.ReturnTypeSubProcessor_voidmethodreturns_description(BindingLabelProvider
.getBindingLabel(binding,
BindingLabelProvider.DEFAULT_TEXTFLAGS));
Images image = Images.correction_change;
LinkedCorrectionProposal proposal =
new LinkedCorrectionProposal(label, rewrite, 6, context.getDocument(), image);
ImportRewrite imports = proposal.createImportRewrite(astRoot);
ImportRewriteContext importRewriteContext =
new ContextSensitiveImportRewriteContext(methodDeclaration, imports);
Type newReturnType = imports.addImport(binding, ast, importRewriteContext);
if (methodDeclaration.isConstructor()) {
rewrite.set(methodDeclaration, MethodDeclaration.CONSTRUCTOR_PROPERTY, Boolean.FALSE, null);
rewrite.set(methodDeclaration, MethodDeclaration.RETURN_TYPE2_PROPERTY, newReturnType, null);
} else {
rewrite.replace(methodDeclaration.getReturnType2(), newReturnType, null);
}
String key = "return_type"; //$NON-NLS-1$
// proposal.addLinkedPosition(rewrite.track(newReturnType), true, key);
ITypeBinding[] bindings = ASTResolving.getRelaxingTypes(ast, binding);
// for (int i = 0; i < bindings.length; i++)
// {
// proposal.addLinkedPositionProposal(key, bindings[i]);
// }
Javadoc javadoc = methodDeclaration.getJavadoc();
if (javadoc != null) {
TagElement newTag = ast.newTagElement();
newTag.setTagName(TagElement.TAG_RETURN);
TextElement commentStart = ast.newTextElement();
newTag.fragments().add(commentStart);
JavadocTagsSubProcessor.insertTag(rewrite.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY), newTag, null);
// proposal.addLinkedPosition(rewrite.track(commentStart), false, "comment_start"); //$NON-NLS-1$
}
proposals.add(proposal);
}
ASTRewrite rewrite = ASTRewrite.create(decl.getAST());
rewrite.remove(returnStatement.getExpression(), null);
String label = CorrectionMessages.INSTANCE.ReturnTypeSubProcessor_removereturn_description();
Images image = Images.correction_change;
ASTRewriteCorrectionProposal proposal =
new ASTRewriteCorrectionProposal(label, rewrite, 5, context.getDocument(), image);
proposals.add(proposal);
}
}
public static void addMissingReturnTypeProposals(InvocationContext context, IProblemLocation problem,
Collection<ICommandAccess> proposals) {
CompilationUnit astRoot = context.getASTRoot();
ASTNode selectedNode = problem.getCoveringNode(astRoot);
if (selectedNode == null) {
return;
}
BodyDeclaration decl = ASTResolving.findParentBodyDeclaration(selectedNode);
if (decl instanceof MethodDeclaration) {
MethodDeclaration methodDeclaration = (MethodDeclaration)decl;
ReturnStatementCollector eval = new ReturnStatementCollector();
decl.accept(eval);
AST ast = astRoot.getAST();
ITypeBinding typeBinding = eval.getTypeBinding(decl.getAST());
typeBinding = Bindings.normalizeTypeBinding(typeBinding);
if (typeBinding == null) {
typeBinding = ast.resolveWellKnownType("void"); //$NON-NLS-1$
}
if (typeBinding.isWildcardType()) {
typeBinding = ASTResolving.normalizeWildcardType(typeBinding, true, ast);
}
ASTRewrite rewrite = ASTRewrite.create(ast);
String label =
CorrectionMessages.INSTANCE.ReturnTypeSubProcessor_missingreturntype_description(BindingLabelProvider
.getBindingLabel(typeBinding,
BindingLabelProvider.DEFAULT_TEXTFLAGS));
Images image = Images.correction_change;
LinkedCorrectionProposal proposal =
new LinkedCorrectionProposal(label, rewrite, 6, context.getDocument(), image);
ImportRewrite imports = proposal.createImportRewrite(astRoot);
ImportRewriteContext importRewriteContext = new ContextSensitiveImportRewriteContext(decl, imports);
Type type = imports.addImport(typeBinding, ast, importRewriteContext);
rewrite.set(methodDeclaration, MethodDeclaration.RETURN_TYPE2_PROPERTY, type, null);
rewrite.set(methodDeclaration, MethodDeclaration.CONSTRUCTOR_PROPERTY, Boolean.FALSE, null);
Javadoc javadoc = methodDeclaration.getJavadoc();
if (javadoc != null && typeBinding != null) {
TagElement newTag = ast.newTagElement();
newTag.setTagName(TagElement.TAG_RETURN);
TextElement commentStart = ast.newTextElement();
newTag.fragments().add(commentStart);
JavadocTagsSubProcessor.insertTag(rewrite.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY), newTag, null);
// proposal.addLinkedPosition(rewrite.track(commentStart), false, "comment_start"); //$NON-NLS-1$
}
String key = "return_type"; //$NON-NLS-1$
// proposal.addLinkedPosition(rewrite.track(type), true, key);
// if (typeBinding != null)
// {
// ITypeBinding[] bindings = ASTResolving.getRelaxingTypes(ast, typeBinding);
// for (int i = 0; i < bindings.length; i++)
// {
// proposal.addLinkedPositionProposal(key, bindings[i]);
// }
// }
proposals.add(proposal);
// change to constructor
ASTNode parentType = ASTResolving.findParentType(decl);
if (parentType instanceof AbstractTypeDeclaration) {
boolean isInterface = parentType instanceof TypeDeclaration && ((TypeDeclaration)parentType).isInterface();
if (!isInterface) {
String constructorName = ((AbstractTypeDeclaration)parentType).getName().getIdentifier();
ASTNode nameNode = methodDeclaration.getName();
label =
CorrectionMessages.INSTANCE.ReturnTypeSubProcessor_wrongconstructorname_description(constructorName);
proposals.add(new ReplaceCorrectionProposal(label, nameNode.getStartPosition(), nameNode.getLength(),
constructorName, 5, context.getDocument()));
}
}
}
}
public static void addMissingReturnStatementProposals(InvocationContext context, IProblemLocation problem,
Collection<ICommandAccess> proposals) {
ASTNode selectedNode = problem.getCoveringNode(context.getASTRoot());
if (selectedNode == null) {
return;
}
BodyDeclaration decl = ASTResolving.findParentBodyDeclaration(selectedNode);
if (decl instanceof MethodDeclaration) {
MethodDeclaration methodDecl = (MethodDeclaration)decl;
Block block = methodDecl.getBody();
if (block == null) {
return;
}
ReturnStatement existingStatement =
(selectedNode instanceof ReturnStatement) ? (ReturnStatement)selectedNode : null;
proposals
.add(new MissingReturnTypeCorrectionProposal(methodDecl, existingStatement, 6, context.getDocument()));
Type returnType = methodDecl.getReturnType2();
if (returnType != null && !"void".equals(ASTNodes.asString(returnType))) { //$NON-NLS-1$
AST ast = methodDecl.getAST();
ASTRewrite rewrite = ASTRewrite.create(ast);
rewrite.replace(returnType, ast.newPrimitiveType(PrimitiveType.VOID), null);
Javadoc javadoc = methodDecl.getJavadoc();
if (javadoc != null) {
TagElement tagElement = JavadocTagsSubProcessor.findTag(javadoc, TagElement.TAG_RETURN, null);
if (tagElement != null) {
rewrite.remove(tagElement, null);
}
}
String label = CorrectionMessages.INSTANCE.ReturnTypeSubProcessor_changetovoid_description();
Images image = Images.correction_change;
ASTRewriteCorrectionProposal proposal =
new ASTRewriteCorrectionProposal(label, rewrite, 5, context.getDocument(), image);
proposals.add(proposal);
}
}
}
public static void addMethodRetunsVoidProposals(InvocationContext context, IProblemLocation problem,
Collection<ICommandAccess> proposals) {
CompilationUnit astRoot = context.getASTRoot();
ASTNode selectedNode = problem.getCoveringNode(astRoot);
if (!(selectedNode instanceof ReturnStatement)) {
return;
}
ReturnStatement returnStatement = (ReturnStatement)selectedNode;
Expression expression = returnStatement.getExpression();
if (expression == null) {
return;
}
BodyDeclaration decl = ASTResolving.findParentBodyDeclaration(selectedNode);
if (decl instanceof MethodDeclaration) {
MethodDeclaration methDecl = (MethodDeclaration)decl;
Type retType = methDecl.getReturnType2();
if (retType == null || retType.resolveBinding() == null) {
return;
}
TypeMismatchSubProcessor.addChangeSenderTypeProposals(context, expression, retType.resolveBinding(), false, 4,
proposals);
}
}
}