1 11 12 package org.eclipse.jdt.internal.ui.text.correction; 13 14 import java.util.Arrays ; 15 import java.util.Collection ; 16 import java.util.HashSet ; 17 import java.util.List ; 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 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 KEY_NAME= "name"; private final String KEY_TYPE= "type"; 69 private final int fVariableKind; 70 private final ASTNode fNodeToAssign; 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); 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); 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 { 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 [] 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 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)); 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 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 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 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 decls= (List ) newTypeDecl.getStructuralProperty(property); 243 AST ast= newTypeDecl.getAST(); 244 String [] varNames= suggestFieldNames(fTypeBinding, expression, modifiers); 245 for (int i= 0; i < varNames.length; i++) { 246 addLinkedPositionProposal(KEY_NAME, varNames[i], null); 247 } 248 String 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 [] 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 [] 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 getUsedVariableNames() { 288 return Arrays.asList(ASTResolving.getUsedVariableNames(fNodeToAssign)); 289 } 290 291 private int findAssignmentInsertIndex(List statements) { 292 293 HashSet paramsBefore= new HashSet (); 294 List 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 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 343 public int getVariableKind() { 344 return fVariableKind; 345 } 346 347 348 } 349 | Popular Tags |