1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 * Benjamin Muskalla - [quick fix] Create Method in void context should 'box' void. - https://bugs.eclipse.org/bugs/show_bug.cgi?id=107985
11 *******************************************************************************/
12 package org.eclipse.jdt.internal.ui.text.correction.proposals;
14 import java.util.List;
16 import org.eclipse.swt.graphics.Image;
18 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.jdt.core.ICompilationUnit;
21 import org.eclipse.jdt.core.IJavaProject;
22 import org.eclipse.jdt.core.NamingConventions;
23 import org.eclipse.jdt.core.dom.AST;
24 import org.eclipse.jdt.core.dom.ASTNode;
25 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
26 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
27 import org.eclipse.jdt.core.dom.Expression;
28 import org.eclipse.jdt.core.dom.ExpressionStatement;
29 import org.eclipse.jdt.core.dom.IBinding;
30 import org.eclipse.jdt.core.dom.IExtendedModifier;
31 import org.eclipse.jdt.core.dom.ITypeBinding;
32 import org.eclipse.jdt.core.dom.MethodDeclaration;
33 import org.eclipse.jdt.core.dom.MethodInvocation;
34 import org.eclipse.jdt.core.dom.Modifier;
35 import org.eclipse.jdt.core.dom.Name;
36 import org.eclipse.jdt.core.dom.ParameterizedType;
37 import org.eclipse.jdt.core.dom.PrimitiveType;
38 import org.eclipse.jdt.core.dom.SimpleName;
39 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
40 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
41 import org.eclipse.jdt.core.dom.Type;
42 import org.eclipse.jdt.core.dom.TypeDeclaration;
43 import org.eclipse.jdt.core.dom.TypeParameter;
44 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
45 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
47 import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
48 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
49 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
50 import org.eclipse.jdt.internal.corext.dom.Bindings;
52 import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
53 import org.eclipse.jdt.internal.ui.text.correction.ModifierCorrectionSubProcessor;
55 public class NewMethodCorrectionProposal extends AbstractMethodCorrectionProposal {
57 private static final String KEY_NAME= "name"; //$NON-NLS-1$
58 private static final String KEY_TYPE= "type"; //$NON-NLS-1$
60 private List<Expression> fArguments;
62 // invocationNode is MethodInvocation, ConstructorInvocation, SuperConstructorInvocation, ClassInstanceCreation, SuperMethodInvocation
63 public NewMethodCorrectionProposal(String label, ICompilationUnit targetCU, ASTNode invocationNode, List<Expression> arguments, ITypeBinding binding, int relevance, Image image) {
64 super(label, targetCU, invocationNode, binding, relevance, image);
65 fArguments= arguments;
68 private int evaluateModifiers(ASTNode targetTypeDecl) {
69 if (getSenderBinding().isAnnotation()) {
72 if (getSenderBinding().isInterface()) {
73 // for interface and annotation members copy the modifiers from an existing field
74 MethodDeclaration[] methodDecls= ((TypeDeclaration) targetTypeDecl).getMethods();
75 if (methodDecls.length > 0) {
76 return methodDecls[0].getModifiers();
80 ASTNode invocationNode= getInvocationNode();
81 if (invocationNode instanceof MethodInvocation) {
83 Expression expression= ((MethodInvocation)invocationNode).getExpression();
84 if (expression != null) {
85 if (expression instanceof Name && ((Name) expression).resolveBinding().getKind() == IBinding.TYPE) {
86 modifiers |= Modifier.STATIC;
88 } else if (ASTResolving.isInStaticContext(invocationNode)) {
89 modifiers |= Modifier.STATIC;
91 ASTNode node= ASTResolving.findParentType(invocationNode);
92 if (targetTypeDecl.equals(node)) {
93 modifiers |= Modifier.PRIVATE;
94 } else if (node instanceof AnonymousClassDeclaration && ASTNodes.isParent(node, targetTypeDecl)) {
95 modifiers |= Modifier.PROTECTED;
96 if (ASTResolving.isInStaticContext(node) && expression == null) {
97 modifiers |= Modifier.STATIC;
100 modifiers |= Modifier.PUBLIC;
104 return Modifier.PUBLIC;
108 * @see org.eclipse.jdt.internal.ui.text.correction.proposals.AbstractMethodCorrectionProposal#addNewModifiers(org.eclipse.jdt.core.dom.rewrite.ASTRewrite, org.eclipse.jdt.core.dom.ASTNode, java.util.List)
111 protected void addNewModifiers(ASTRewrite rewrite, ASTNode targetTypeDecl, List<IExtendedModifier> modifiers) {
112 modifiers.addAll(rewrite.getAST().newModifiers(evaluateModifiers(targetTypeDecl)));
113 ModifierCorrectionSubProcessor.installLinkedVisibilityProposals(getLinkedProposalModel(), rewrite, modifiers, getSenderBinding().isInterface());
117 * @see org.eclipse.jdt.internal.ui.text.correction.proposals.AbstractMethodCorrectionProposal#isConstructor()
120 protected boolean isConstructor() {
121 ASTNode node= getInvocationNode();
123 return node.getNodeType() != ASTNode.METHOD_INVOCATION && node.getNodeType() != ASTNode.SUPER_METHOD_INVOCATION;
127 * @see org.eclipse.jdt.internal.ui.text.correction.proposals.AbstractMethodCorrectionProposal#getNewName(org.eclipse.jdt.core.dom.rewrite.ASTRewrite)
130 protected SimpleName getNewName(ASTRewrite rewrite) {
131 ASTNode invocationNode= getInvocationNode();
133 if (invocationNode instanceof MethodInvocation) {
134 name= ((MethodInvocation)invocationNode).getName().getIdentifier();
135 } else if (invocationNode instanceof SuperMethodInvocation) {
136 name= ((SuperMethodInvocation)invocationNode).getName().getIdentifier();
138 name= getSenderBinding().getName(); // name of the class
140 AST ast= rewrite.getAST();
141 SimpleName newNameNode= ast.newSimpleName(name);
142 addLinkedPosition(rewrite.track(newNameNode), false, KEY_NAME);
144 ASTNode invocationName= getInvocationNameNode();
145 if (invocationName != null && invocationName.getAST() == ast) { // in the same CU
146 addLinkedPosition(rewrite.track(invocationName), true, KEY_NAME);
151 private ASTNode getInvocationNameNode() {
152 ASTNode node= getInvocationNode();
153 if (node instanceof MethodInvocation) {
154 return ((MethodInvocation)node).getName();
155 } else if (node instanceof SuperMethodInvocation) {
156 return ((SuperMethodInvocation)node).getName();
157 } else if (node instanceof ClassInstanceCreation) {
158 Type type= ((ClassInstanceCreation)node).getType();
159 while (type instanceof ParameterizedType) {
160 type= ((ParameterizedType) type).getType();
168 * @see org.eclipse.jdt.internal.ui.text.correction.proposals.AbstractMethodCorrectionProposal#getNewMethodType(org.eclipse.jdt.core.dom.rewrite.ASTRewrite)
171 protected Type getNewMethodType(ASTRewrite rewrite) throws CoreException {
172 ASTNode node= getInvocationNode();
173 AST ast= rewrite.getAST();
175 Type newTypeNode= null;
176 ITypeBinding[] otherProposals= null;
178 ImportRewriteContext importRewriteContext= new ContextSensitiveImportRewriteContext(node, getImportRewrite());
179 if (node.getParent() instanceof MethodInvocation) {
180 MethodInvocation parent= (MethodInvocation) node.getParent();
181 if (parent.getExpression() == node) {
182 ITypeBinding[] bindings= ASTResolving.getQualifierGuess(node.getRoot(), parent.getName().getIdentifier(), parent.arguments(), getSenderBinding());
183 if (bindings.length > 0) {
184 newTypeNode= getImportRewrite().addImport(bindings[0], ast, importRewriteContext);
185 otherProposals= bindings;
189 if (newTypeNode == null) {
190 ITypeBinding binding= ASTResolving.guessBindingForReference(node);
191 if (binding != null && binding.isWildcardType()) {
192 binding= ASTResolving.normalizeWildcardType(binding, false, ast);
194 if (binding != null) {
195 newTypeNode= getImportRewrite().addImport(binding, ast, importRewriteContext);
197 ASTNode parent= node.getParent();
198 if (parent instanceof ExpressionStatement) {
199 newTypeNode= ast.newPrimitiveType(PrimitiveType.VOID);
201 newTypeNode= ASTResolving.guessTypeForReference(ast, node);
202 if (newTypeNode == null) {
203 newTypeNode= ast.newSimpleType(ast.newSimpleName("Object")); //$NON-NLS-1$
209 addLinkedPosition(rewrite.track(newTypeNode), false, KEY_TYPE);
210 if (otherProposals != null) {
211 for (int i= 0; i < otherProposals.length; i++) {
212 addLinkedPositionProposal(KEY_TYPE, otherProposals[i]);
220 * @see org.eclipse.jdt.internal.ui.text.correction.proposals.AbstractMethodCorrectionProposal#addNewParameters(org.eclipse.jdt.core.dom.rewrite.ASTRewrite, java.util.List, java.util.List)
223 protected void addNewParameters(ASTRewrite rewrite, List<String> takenNames, List<SingleVariableDeclaration> params) throws CoreException {
224 AST ast= rewrite.getAST();
226 List<Expression> arguments= fArguments;
227 ImportRewriteContext context= new ContextSensitiveImportRewriteContext(ASTResolving.findParentBodyDeclaration(getInvocationNode()), getImportRewrite());
229 for (int i= 0; i < arguments.size(); i++) {
230 Expression elem= arguments.get(i);
231 SingleVariableDeclaration param= ast.newSingleVariableDeclaration();
234 String argTypeKey= "arg_type_" + i; //$NON-NLS-1$
235 Type type= evaluateParameterType(ast, elem, argTypeKey, context);
239 String argNameKey= "arg_name_" + i; //$NON-NLS-1$
240 String name= evaluateParameterName(takenNames, elem, type, argNameKey);
241 param.setName(ast.newSimpleName(name));
245 addLinkedPosition(rewrite.track(param.getType()), false, argTypeKey);
246 addLinkedPosition(rewrite.track(param.getName()), false, argNameKey);
250 private Type evaluateParameterType(AST ast, Expression elem, String key, ImportRewriteContext context) {
251 ITypeBinding binding= Bindings.normalizeTypeBinding(elem.resolveTypeBinding());
252 if (binding != null && binding.isWildcardType()) {
253 binding= ASTResolving.normalizeWildcardType(binding, true, ast);
255 if (binding != null) {
256 ITypeBinding[] typeProposals= ASTResolving.getRelaxingTypes(ast, binding);
257 for (int i= 0; i < typeProposals.length; i++) {
258 addLinkedPositionProposal(key, typeProposals[i]);
260 return getImportRewrite().addImport(binding, ast, context);
262 return ast.newSimpleType(ast.newSimpleName("Object")); //$NON-NLS-1$
265 private String evaluateParameterName(List<String> takenNames, Expression argNode, Type type, String key) {
266 IJavaProject project= getCompilationUnit().getJavaProject();
267 String[] names= StubUtility.getVariableNameSuggestions(NamingConventions.VK_PARAMETER, project, type, argNode, takenNames);
268 for (int i= 0; i < names.length; i++) {
269 addLinkedPositionProposal(key, names[i], null);
271 String favourite= names[0];
272 takenNames.add(favourite);
277 * @see org.eclipse.jdt.internal.ui.text.correction.proposals.AbstractMethodCorrectionProposal#addNewExceptions(org.eclipse.jdt.core.dom.rewrite.ASTRewrite, java.util.List)
280 protected void addNewExceptions(ASTRewrite rewrite, List<Name> exceptions) throws CoreException {
284 * @see org.eclipse.jdt.internal.ui.text.correction.proposals.AbstractMethodCorrectionProposal#addNewTypeParameters(org.eclipse.jdt.core.dom.rewrite.ASTRewrite, java.util.List, java.util.List)
287 protected void addNewTypeParameters(ASTRewrite rewrite, List<String> takenNames, List<TypeParameter> params) throws CoreException {