KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > text > correction > AssignToVariableAssistProposal


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.jdt.internal.ui.text.correction;
13
14 import java.util.Arrays JavaDoc;
15 import java.util.Collection JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.List JavaDoc;
18
19 import org.eclipse.core.runtime.CoreException;
20
21 import org.eclipse.jdt.core.ICompilationUnit;
22 import org.eclipse.jdt.core.IJavaProject;
23 import org.eclipse.jdt.core.dom.AST;
24 import org.eclipse.jdt.core.dom.ASTNode;
25 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
26 import org.eclipse.jdt.core.dom.Assignment;
27 import org.eclipse.jdt.core.dom.Block;
28 import org.eclipse.jdt.core.dom.BodyDeclaration;
29 import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
30 import org.eclipse.jdt.core.dom.CompilationUnit;
31 import org.eclipse.jdt.core.dom.Expression;
32 import org.eclipse.jdt.core.dom.ExpressionStatement;
33 import org.eclipse.jdt.core.dom.FieldAccess;
34 import org.eclipse.jdt.core.dom.FieldDeclaration;
35 import org.eclipse.jdt.core.dom.ITypeBinding;
36 import org.eclipse.jdt.core.dom.IVariableBinding;
37 import org.eclipse.jdt.core.dom.Initializer;
38 import org.eclipse.jdt.core.dom.MethodDeclaration;
39 import org.eclipse.jdt.core.dom.Modifier;
40 import org.eclipse.jdt.core.dom.SimpleName;
41 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
42 import org.eclipse.jdt.core.dom.Statement;
43 import org.eclipse.jdt.core.dom.Type;
44 import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
45 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
46 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
47
48 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
49 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
50 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
51 import org.eclipse.jdt.internal.corext.dom.Bindings;
52 import org.eclipse.jdt.internal.corext.util.Messages;
53
54 import org.eclipse.jdt.internal.ui.JavaPluginImages;
55
56 /**
57  * Proposals for 'Assign to variable' quick assist
58  * - Assign an expression from an ExpressionStatement to a local or field
59  * - Assign a parameter to a field
60  * */

61 public class AssignToVariableAssistProposal extends LinkedCorrectionProposal {
62
63     public static final int LOCAL= 1;
64     public static final int FIELD= 2;
65
66     private final String JavaDoc KEY_NAME= "name"; //$NON-NLS-1$
67
private final String JavaDoc KEY_TYPE= "type"; //$NON-NLS-1$
68

69     private final int fVariableKind;
70     private final ASTNode fNodeToAssign; // ExpressionStatement or SingleVariableDeclaration
71
private final ITypeBinding fTypeBinding;
72
73     private VariableDeclarationFragment fExistingFragment;
74     
75     public AssignToVariableAssistProposal(ICompilationUnit cu, int variableKind, ExpressionStatement node, ITypeBinding typeBinding, int relevance) {
76         super("", cu, null, relevance, null); //$NON-NLS-1$
77

78         fVariableKind= variableKind;
79         fNodeToAssign= node;
80         if (typeBinding.isWildcardType()) {
81             typeBinding= ASTResolving.normalizeWildcardType(typeBinding, true, node.getAST());
82         }
83         
84         fTypeBinding= typeBinding;
85         if (variableKind == LOCAL) {
86             setDisplayName(CorrectionMessages.AssignToVariableAssistProposal_assigntolocal_description);
87             setImage(JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_LOCAL));
88         } else {
89             setDisplayName(CorrectionMessages.AssignToVariableAssistProposal_assigntofield_description);
90             setImage(JavaPluginImages.get(JavaPluginImages.IMG_FIELD_PRIVATE));
91         }
92         createImportRewrite((CompilationUnit) node.getRoot());
93     }
94
95     public AssignToVariableAssistProposal(ICompilationUnit cu, SingleVariableDeclaration parameter, VariableDeclarationFragment existingFragment, ITypeBinding typeBinding, int relevance) {
96         super("", cu, null, relevance, null); //$NON-NLS-1$
97

98         fVariableKind= FIELD;
99         fNodeToAssign= parameter;
100         fTypeBinding= typeBinding;
101         fExistingFragment= existingFragment;
102         
103         if (existingFragment == null) {
104             setDisplayName(CorrectionMessages.AssignToVariableAssistProposal_assignparamtofield_description);
105         } else {
106             setDisplayName(Messages.format(CorrectionMessages.AssignToVariableAssistProposal_assigntoexistingfield_description, existingFragment.getName().getIdentifier()));
107         }
108         setImage(JavaPluginImages.get(JavaPluginImages.IMG_FIELD_PRIVATE));
109     }
110
111     protected ASTRewrite getRewrite() throws CoreException {
112         if (fVariableKind == FIELD) {
113             return doAddField();
114         } else { // LOCAL
115
return doAddLocal();
116         }
117     }
118
119     private ASTRewrite doAddLocal() throws CoreException {
120         Expression expression= ((ExpressionStatement) fNodeToAssign).getExpression();
121         AST ast= fNodeToAssign.getAST();
122
123         ASTRewrite rewrite= ASTRewrite.create(ast);
124         
125         createImportRewrite((CompilationUnit) fNodeToAssign.getRoot());
126
127         String JavaDoc[] varNames= suggestLocalVariableNames(fTypeBinding, expression);
128         for (int i= 0; i < varNames.length; i++) {
129             addLinkedPositionProposal(KEY_NAME, varNames[i], null);
130         }
131
132         VariableDeclarationFragment newDeclFrag= ast.newVariableDeclarationFragment();
133         newDeclFrag.setName(ast.newSimpleName(varNames[0]));
134         newDeclFrag.setInitializer((Expression) rewrite.createCopyTarget(expression));
135
136         // trick for bug 43248: use an VariableDeclarationExpression and keep the ExpressionStatement
137
VariableDeclarationExpression newDecl= ast.newVariableDeclarationExpression(newDeclFrag);
138
139         Type type= evaluateType(ast);
140         newDecl.setType(type);
141
142         rewrite.replace(expression, newDecl, null);
143
144         addLinkedPosition(rewrite.track(newDeclFrag.getName()), true, KEY_NAME);
145         addLinkedPosition(rewrite.track(newDecl.getType()), false, KEY_TYPE);
146         setEndPosition(rewrite.track(fNodeToAssign)); // set cursor after expression statement
147

148         return rewrite;
149     }
150
151     private ASTRewrite doAddField() throws CoreException {
152         boolean isParamToField= fNodeToAssign.getNodeType() == ASTNode.SINGLE_VARIABLE_DECLARATION;
153
154         ASTNode newTypeDecl= ASTResolving.findParentType(fNodeToAssign);
155         if (newTypeDecl == null) {
156             return null;
157         }
158
159         Expression expression= isParamToField ? ((SingleVariableDeclaration) fNodeToAssign).getName() : ((ExpressionStatement) fNodeToAssign).getExpression();
160
161         AST ast= newTypeDecl.getAST();
162         ASTRewrite rewrite= ASTRewrite.create(ast);
163
164         createImportRewrite((CompilationUnit) fNodeToAssign.getRoot());
165         
166         BodyDeclaration bodyDecl= ASTResolving.findParentBodyDeclaration(fNodeToAssign);
167         Block body;
168         if (bodyDecl instanceof MethodDeclaration) {
169             body= ((MethodDeclaration) bodyDecl).getBody();
170         } else if (bodyDecl instanceof Initializer) {
171             body= ((Initializer) bodyDecl).getBody();
172         } else {
173             return null;
174         }
175
176         boolean isAnonymous= newTypeDecl.getNodeType() == ASTNode.ANONYMOUS_CLASS_DECLARATION;
177         boolean isStatic= Modifier.isStatic(bodyDecl.getModifiers()) && !isAnonymous;
178         boolean isConstructorParam= isParamToField && fNodeToAssign.getParent() instanceof MethodDeclaration && ((MethodDeclaration) fNodeToAssign.getParent()).isConstructor();
179         int modifiers= Modifier.PRIVATE;
180         if (isStatic) {
181             modifiers |= Modifier.STATIC;
182         } else if (isConstructorParam) {
183             modifiers |= Modifier.FINAL;
184         }
185
186         VariableDeclarationFragment newDeclFrag= addFieldDeclaration(rewrite, newTypeDecl, modifiers, expression);
187         String JavaDoc varName= newDeclFrag.getName().getIdentifier();
188
189         Assignment assignment= ast.newAssignment();
190         assignment.setRightHandSide((Expression) rewrite.createCopyTarget(expression));
191
192         boolean needsThis= StubUtility.useThisForFieldAccess(getCompilationUnit().getJavaProject());
193         if (isParamToField) {
194             needsThis |= varName.equals(((SimpleName) expression).getIdentifier());
195         }
196
197         SimpleName accessName= ast.newSimpleName(varName);
198         if (needsThis) {
199             FieldAccess fieldAccess= ast.newFieldAccess();
200             fieldAccess.setName(accessName);
201             if (isStatic) {
202                 String JavaDoc typeName= ((AbstractTypeDeclaration) newTypeDecl).getName().getIdentifier();
203                 fieldAccess.setExpression(ast.newSimpleName(typeName));
204             } else {
205                 fieldAccess.setExpression(ast.newThisExpression());
206             }
207             assignment.setLeftHandSide(fieldAccess);
208         } else {
209             assignment.setLeftHandSide(accessName);
210         }
211
212         ASTNode selectionNode;
213         if (isParamToField) {
214             // assign parameter to field
215
ExpressionStatement statement= ast.newExpressionStatement(assignment);
216             int insertIdx= findAssignmentInsertIndex(body.statements());
217             rewrite.getListRewrite(body, Block.STATEMENTS_PROPERTY).insertAt(statement, insertIdx, null);
218             selectionNode= statement;
219
220         } else {
221             rewrite.replace(expression, assignment, null);
222             selectionNode= fNodeToAssign;
223         }
224
225         addLinkedPosition(rewrite.track(newDeclFrag.getName()), false, KEY_NAME);
226         if (!isParamToField) {
227             FieldDeclaration fieldDeclaration= (FieldDeclaration) newDeclFrag.getParent();
228             addLinkedPosition(rewrite.track(fieldDeclaration.getType()), false, KEY_TYPE);
229         }
230         addLinkedPosition(rewrite.track(accessName), true, KEY_NAME);
231         setEndPosition(rewrite.track(selectionNode));
232
233         return rewrite;
234     }
235
236     private VariableDeclarationFragment addFieldDeclaration(ASTRewrite rewrite, ASTNode newTypeDecl, int modifiers, Expression expression) throws CoreException {
237         if (fExistingFragment != null) {
238             return fExistingFragment;
239         }
240         
241         ChildListPropertyDescriptor property= ASTNodes.getBodyDeclarationsProperty(newTypeDecl);
242         List JavaDoc decls= (List JavaDoc) newTypeDecl.getStructuralProperty(property);
243         AST ast= newTypeDecl.getAST();
244         String JavaDoc[] varNames= suggestFieldNames(fTypeBinding, expression, modifiers);
245         for (int i= 0; i < varNames.length; i++) {
246             addLinkedPositionProposal(KEY_NAME, varNames[i], null);
247         }
248         String JavaDoc varName= varNames[0];
249
250         VariableDeclarationFragment newDeclFrag= ast.newVariableDeclarationFragment();
251         newDeclFrag.setName(ast.newSimpleName(varName));
252
253         FieldDeclaration newDecl= ast.newFieldDeclaration(newDeclFrag);
254
255         Type type= evaluateType(ast);
256         newDecl.setType(type);
257         newDecl.modifiers().addAll(ASTNodeFactory.newModifiers(ast, modifiers));
258         
259         ModifierCorrectionSubProcessor.installLinkedVisibilityProposals(getLinkedProposalModel(), rewrite, newDecl.modifiers(), false);
260
261         int insertIndex= findFieldInsertIndex(decls, fNodeToAssign.getStartPosition());
262         rewrite.getListRewrite(newTypeDecl, property).insertAt(newDecl, insertIndex, null);
263         
264         return newDeclFrag;
265     }
266     
267     
268     private Type evaluateType(AST ast) throws CoreException {
269         ITypeBinding[] proposals= ASTResolving.getRelaxingTypes(ast, fTypeBinding);
270         for (int i= 0; i < proposals.length; i++) {
271             addLinkedPositionProposal(KEY_TYPE, proposals[i]);
272         }
273         return getImportRewrite().addImport(fTypeBinding, ast);
274     }
275
276     private String JavaDoc[] suggestLocalVariableNames(ITypeBinding binding, Expression expression) {
277         IJavaProject project= getCompilationUnit().getJavaProject();
278         return StubUtility.getVariableNameSuggestions(StubUtility.LOCAL, project, binding, expression, getUsedVariableNames());
279     }
280
281     private String JavaDoc[] suggestFieldNames(ITypeBinding binding, Expression expression, int modifiers) {
282         IJavaProject project= getCompilationUnit().getJavaProject();
283         int varKind= Modifier.isStatic(modifiers) ? StubUtility.STATIC_FIELD : StubUtility.INSTANCE_FIELD;
284         return StubUtility.getVariableNameSuggestions(varKind, project, binding, expression, getUsedVariableNames());
285     }
286
287     private Collection JavaDoc getUsedVariableNames() {
288         return Arrays.asList(ASTResolving.getUsedVariableNames(fNodeToAssign));
289     }
290
291     private int findAssignmentInsertIndex(List JavaDoc statements) {
292
293         HashSet JavaDoc paramsBefore= new HashSet JavaDoc();
294         List JavaDoc params = ((MethodDeclaration) fNodeToAssign.getParent()).parameters();
295         for (int i = 0; i < params.size() && (params.get(i) != fNodeToAssign); i++) {
296             SingleVariableDeclaration decl= (SingleVariableDeclaration) params.get(i);
297             paramsBefore.add(decl.getName().getIdentifier());
298         }
299
300         int i= 0;
301         for (i = 0; i < statements.size(); i++) {
302             Statement curr= (Statement) statements.get(i);
303             switch (curr.getNodeType()) {
304                 case ASTNode.CONSTRUCTOR_INVOCATION:
305                 case ASTNode.SUPER_CONSTRUCTOR_INVOCATION:
306                     break;
307                 case ASTNode.EXPRESSION_STATEMENT:
308                     Expression expr= ((ExpressionStatement) curr).getExpression();
309                     if (expr instanceof Assignment) {
310                         Assignment assignment= (Assignment) expr;
311                         Expression rightHand = assignment.getRightHandSide();
312                         if (rightHand instanceof SimpleName && paramsBefore.contains(((SimpleName) rightHand).getIdentifier())) {
313                             IVariableBinding binding = Bindings.getAssignedVariable(assignment);
314                             if (binding == null || binding.isField()) {
315                                 break;
316                             }
317                         }
318                     }
319                     return i;
320                 default:
321                     return i;
322
323             }
324         }
325         return i;
326
327     }
328
329     private int findFieldInsertIndex(List JavaDoc decls, int currPos) {
330         for (int i= decls.size() - 1; i >= 0; i--) {
331             ASTNode curr= (ASTNode) decls.get(i);
332             if (curr instanceof FieldDeclaration && currPos > curr.getStartPosition() + curr.getLength()) {
333                 return i + 1;
334             }
335         }
336         return 0;
337     }
338
339     /**
340      * Returns the variable kind.
341      * @return int
342      */

343     public int getVariableKind() {
344         return fVariableKind;
345     }
346
347
348 }
349
Popular Tags