1 11 package org.eclipse.jdt.internal.corext.fix; 12 13 import java.util.ArrayList ; 14 import java.util.HashMap ; 15 import java.util.HashSet ; 16 import java.util.Iterator ; 17 import java.util.List ; 18 19 import org.eclipse.text.edits.TextEditGroup; 20 21 import org.eclipse.core.runtime.CoreException; 22 23 import org.eclipse.jdt.core.dom.ASTNode; 24 import org.eclipse.jdt.core.dom.Assignment; 25 import org.eclipse.jdt.core.dom.Block; 26 import org.eclipse.jdt.core.dom.CompilationUnit; 27 import org.eclipse.jdt.core.dom.ConstructorInvocation; 28 import org.eclipse.jdt.core.dom.ExpressionStatement; 29 import org.eclipse.jdt.core.dom.FieldDeclaration; 30 import org.eclipse.jdt.core.dom.IBinding; 31 import org.eclipse.jdt.core.dom.IMethodBinding; 32 import org.eclipse.jdt.core.dom.ITypeBinding; 33 import org.eclipse.jdt.core.dom.IVariableBinding; 34 import org.eclipse.jdt.core.dom.MethodDeclaration; 35 import org.eclipse.jdt.core.dom.Modifier; 36 import org.eclipse.jdt.core.dom.SimpleName; 37 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 38 import org.eclipse.jdt.core.dom.Statement; 39 import org.eclipse.jdt.core.dom.TypeDeclaration; 40 import org.eclipse.jdt.core.dom.VariableDeclarationExpression; 41 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 42 import org.eclipse.jdt.core.dom.VariableDeclarationStatement; 43 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 44 45 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 46 import org.eclipse.jdt.internal.corext.dom.GenericVisitor; 47 import org.eclipse.jdt.internal.corext.dom.VariableDeclarationRewrite; 48 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; 49 50 import org.eclipse.jdt.internal.ui.text.correction.ASTResolving; 51 52 public class VariableDeclarationFix extends AbstractFix { 53 54 private static class WrittenNamesFinder extends GenericVisitor { 55 56 private final HashMap fResult; 57 58 public WrittenNamesFinder(HashMap result) { 59 fResult= result; 60 } 61 62 65 public boolean visit(SimpleName node) { 66 if (node.getParent() instanceof VariableDeclarationFragment) 67 return super.visit(node); 68 if (node.getParent() instanceof SingleVariableDeclaration) 69 return super.visit(node); 70 71 IBinding binding= node.resolveBinding(); 72 if (!(binding instanceof IVariableBinding)) 73 return super.visit(node); 74 75 binding= ((IVariableBinding)binding).getVariableDeclaration(); 76 if (ASTResolving.isWriteAccess(node)) { 77 List list; 78 if (fResult.containsKey(binding)) { 79 list= (List )fResult.get(binding); 80 } else { 81 list= new ArrayList (); 82 } 83 list.add(node); 84 fResult.put(binding, list); 85 } 86 87 return super.visit(node); 88 } 89 } 90 91 private static class VariableDeclarationFinder extends GenericVisitor { 92 93 private final CompilationUnit fCompilationUnit; 94 private final List fResult; 95 private final HashMap fWrittenVariables; 96 private final boolean fAddFinalFields; 97 private final boolean fAddFinalParameters; 98 private final boolean fAddFinalLocals; 99 100 public VariableDeclarationFinder(boolean addFinalFields, 101 boolean addFinalParameters, 102 boolean addFinalLocals, 103 final CompilationUnit compilationUnit, final List result, final HashMap writtenNames) { 104 105 super(); 106 fAddFinalFields= addFinalFields; 107 fAddFinalParameters= addFinalParameters; 108 fAddFinalLocals= addFinalLocals; 109 fCompilationUnit= compilationUnit; 110 fResult= result; 111 fWrittenVariables= writtenNames; 112 } 113 114 117 public boolean visit(FieldDeclaration node) { 118 if (fAddFinalFields) 119 return handleFragments(node.fragments(), node); 120 121 return false; 122 } 123 124 127 public boolean visit(VariableDeclarationStatement node) { 128 if (fAddFinalLocals) 129 return handleFragments(node.fragments(), node); 130 131 return false; 132 } 133 134 137 public boolean visit(VariableDeclarationExpression node) { 138 if (fAddFinalLocals && node.fragments().size() == 1) { 139 SimpleName name= ((VariableDeclarationFragment)node.fragments().get(0)).getName(); 140 141 IBinding binding= name.resolveBinding(); 142 if (binding == null) 143 return false; 144 145 if (fWrittenVariables.containsKey(binding)) 146 return false; 147 148 ModifierChangeOperation op= createAddFinalOperation(name, fCompilationUnit, node); 149 if (op == null) 150 return false; 151 152 fResult.add(op); 153 return false; 154 } 155 return false; 156 } 157 158 private boolean handleFragments(List list, ASTNode declaration) { 159 List toChange= new ArrayList (); 160 161 for (Iterator iter= list.iterator(); iter.hasNext();) { 162 VariableDeclarationFragment fragment= (VariableDeclarationFragment)iter.next(); 163 SimpleName name= fragment.getName(); 164 IBinding resolveBinding= name.resolveBinding(); 165 if (canAddFinal(resolveBinding, name, declaration)) { 166 IVariableBinding varbinding= (IVariableBinding)resolveBinding; 167 if (varbinding.isField()) { 168 if (fieldCanBeFinal(fragment, varbinding)) 169 toChange.add(fragment); 170 } else { 171 if (!fWrittenVariables.containsKey(resolveBinding)) 172 toChange.add(fragment); 173 } 174 } 175 } 176 177 if (toChange.size() == 0) 178 return false; 179 180 ModifierChangeOperation op= new ModifierChangeOperation(declaration, toChange, Modifier.FINAL, Modifier.VOLATILE); 181 fResult.add(op); 182 return false; 183 } 184 185 private boolean fieldCanBeFinal(VariableDeclarationFragment fragment, IVariableBinding binding) { 186 if (Modifier.isStatic(((FieldDeclaration)fragment.getParent()).getModifiers())) 187 return false; 188 189 if (!fWrittenVariables.containsKey(binding)) { 190 if (fragment.getInitializer() == null) { return false; 193 } else { 194 return true; 195 } 196 } 197 198 if (fragment.getInitializer() != null) return false; 200 201 ITypeBinding declaringClass= binding.getDeclaringClass(); 202 if (declaringClass == null) 203 return false; 204 205 ArrayList writes= (ArrayList )fWrittenVariables.get(binding); 206 if (!isWrittenInTypeConstructors(binding, writes, declaringClass)) 207 return false; 208 209 HashSet writingConstructorBindings= new HashSet (); 210 ArrayList writingConstructors= new ArrayList (); 211 for (int i= 0; i < writes.size(); i++) { 212 SimpleName name= (SimpleName)writes.get(i); 213 MethodDeclaration constructor= getWritingConstructor(name); 214 if (writingConstructors.contains(constructor)) return false; 216 217 writingConstructors.add(constructor); 218 IMethodBinding constructorBinding= constructor.resolveBinding(); 219 if (constructorBinding == null) 220 return false; 221 222 writingConstructorBindings.add(constructorBinding); 223 } 224 225 for (int i= 0; i < writingConstructors.size(); i++) { 226 MethodDeclaration constructor= (MethodDeclaration)writingConstructors.get(i); 227 if (callsWrittingConstructor(constructor, writingConstructorBindings)) return false; 229 } 230 231 MethodDeclaration constructor= (MethodDeclaration)writingConstructors.get(0); 232 TypeDeclaration typeDecl= (TypeDeclaration)ASTNodes.getParent(constructor, TypeDeclaration.class); 233 if (typeDecl == null) 234 return false; 235 236 MethodDeclaration[] methods= typeDecl.getMethods(); 237 for (int i= 0; i < methods.length; i++) { 238 if (methods[i].isConstructor()) { 239 IMethodBinding methodBinding= methods[i].resolveBinding(); 240 if (methodBinding == null) 241 return false; 242 243 if (!writingConstructorBindings.contains(methodBinding)) { 244 if (!callsWrittingConstructor(methods[i], writingConstructorBindings)) return false; 246 } 247 } 248 } 249 250 return true; 251 } 252 253 private boolean callsWrittingConstructor(MethodDeclaration methodDeclaration, HashSet writingConstructorBindings) { 254 Block body= methodDeclaration.getBody(); 255 if (body == null) 256 return false; 257 258 List statements= body.statements(); 259 if (statements.size() == 0) 260 return false; 261 262 Statement statement= (Statement)statements.get(0); 263 if (!(statement instanceof ConstructorInvocation)) 264 return false; 265 266 ConstructorInvocation invocation= (ConstructorInvocation)statement; 267 IMethodBinding constructorBinding= invocation.resolveConstructorBinding(); 268 if (constructorBinding == null) 269 return false; 270 271 if (writingConstructorBindings.contains(constructorBinding)) { 272 return true; 273 } else { 274 ASTNode declaration= ASTNodes.findDeclaration(constructorBinding, methodDeclaration.getParent()); 275 if (!(declaration instanceof MethodDeclaration)) 276 return false; 277 278 return callsWrittingConstructor((MethodDeclaration)declaration, writingConstructorBindings); 279 } 280 } 281 282 private boolean isWrittenInTypeConstructors(IVariableBinding binding, ArrayList writes, ITypeBinding declaringClass) { 283 284 for (int i= 0; i < writes.size(); i++) { 285 SimpleName name= (SimpleName)writes.get(i); 286 287 MethodDeclaration methodDeclaration= getWritingConstructor(name); 288 if (methodDeclaration == null) 289 return false; 290 291 if (!methodDeclaration.isConstructor()) 292 return false; 293 294 IMethodBinding constructor= methodDeclaration.resolveBinding(); 295 if (constructor == null) 296 return false; 297 298 ITypeBinding declaringClass2= constructor.getDeclaringClass(); 299 if (!declaringClass.equals(declaringClass2)) 300 return false; 301 } 302 303 return true; 304 } 305 306 private MethodDeclaration getWritingConstructor(SimpleName name) { 307 Assignment assignement= (Assignment)ASTNodes.getParent(name, Assignment.class); 308 if (assignement == null) 309 return null; 310 311 ASTNode expression= assignement.getParent(); 312 if (!(expression instanceof ExpressionStatement)) 313 return null; 314 315 ASTNode block= expression.getParent(); 316 if (!(block instanceof Block)) 317 return null; 318 319 ASTNode methodDeclaration= block.getParent(); 320 if (!(methodDeclaration instanceof MethodDeclaration)) 321 return null; 322 323 return (MethodDeclaration)methodDeclaration; 324 } 325 326 329 public boolean visit(VariableDeclarationFragment node) { 330 SimpleName name= node.getName(); 331 332 IBinding binding= name.resolveBinding(); 333 if (binding == null) 334 return false; 335 336 if (fWrittenVariables.containsKey(binding)) 337 return false; 338 339 ModifierChangeOperation op= createAddFinalOperation(name, fCompilationUnit, node); 340 if (op == null) 341 return false; 342 343 fResult.add(op); 344 return false; 345 } 346 347 350 public boolean visit(SingleVariableDeclaration node) { 351 SimpleName name= node.getName(); 352 353 IBinding binding= name.resolveBinding(); 354 if (!(binding instanceof IVariableBinding)) 355 return false; 356 357 IVariableBinding varBinding= (IVariableBinding)binding; 358 if (fWrittenVariables.containsKey(varBinding)) 359 return false; 360 361 if (fAddFinalParameters && fAddFinalLocals) { 362 363 ModifierChangeOperation op= createAddFinalOperation(name, fCompilationUnit, node); 364 if (op == null) 365 return false; 366 367 fResult.add(op); 368 return false; 369 } else if (fAddFinalParameters) { 370 if (!varBinding.isParameter()) 371 return false; 372 373 ModifierChangeOperation op= createAddFinalOperation(name, fCompilationUnit, node); 374 if (op == null) 375 return false; 376 377 fResult.add(op); 378 return false; 379 } else if (fAddFinalLocals) { 380 if (varBinding.isParameter()) 381 return false; 382 383 ModifierChangeOperation op= createAddFinalOperation(name, fCompilationUnit, node); 384 if (op == null) 385 return false; 386 387 fResult.add(op); 388 return false; 389 } 390 return false; 391 } 392 } 393 394 private static class ModifierChangeOperation extends AbstractFixRewriteOperation { 395 396 private final ASTNode fDeclaration; 397 private final List fToChange; 398 private final int fIncludedModifiers; 399 private final int fExcludedModifiers; 400 401 public ModifierChangeOperation(ASTNode declaration, List toChange, int includedModifiers, int excludedModifiers) { 402 fDeclaration= declaration; 403 fToChange= toChange; 404 fIncludedModifiers= includedModifiers; 405 fExcludedModifiers= excludedModifiers; 406 } 407 408 411 public void rewriteAST(CompilationUnitRewrite cuRewrite, List textEditGroups) throws CoreException { 412 ASTRewrite rewrite= cuRewrite.getASTRewrite(); 413 414 TextEditGroup group= createTextEditGroup(FixMessages.VariableDeclarationFix_changeModifierOfUnknownToFinal_description); 415 textEditGroups.add(group); 416 417 if (fDeclaration instanceof VariableDeclarationStatement) { 418 VariableDeclarationFragment[] toChange= (VariableDeclarationFragment[])fToChange.toArray(new VariableDeclarationFragment[fToChange.size()]); 419 VariableDeclarationRewrite.rewriteModifiers((VariableDeclarationStatement)fDeclaration, toChange, fIncludedModifiers, fExcludedModifiers, rewrite, group); 420 } else if (fDeclaration instanceof FieldDeclaration) { 421 VariableDeclarationFragment[] toChange= (VariableDeclarationFragment[])fToChange.toArray(new VariableDeclarationFragment[fToChange.size()]); 422 VariableDeclarationRewrite.rewriteModifiers((FieldDeclaration)fDeclaration, toChange, fIncludedModifiers, fExcludedModifiers, rewrite, group); 423 } else if (fDeclaration instanceof SingleVariableDeclaration) { 424 VariableDeclarationRewrite.rewriteModifiers((SingleVariableDeclaration)fDeclaration, fIncludedModifiers, fExcludedModifiers, rewrite, group); 425 } else if (fDeclaration instanceof VariableDeclarationExpression) { 426 VariableDeclarationRewrite.rewriteModifiers((VariableDeclarationExpression)fDeclaration, fIncludedModifiers, fExcludedModifiers, rewrite, group); 427 } 428 } 429 } 430 431 public static IFix createChangeModifierToFinalFix(final CompilationUnit compilationUnit, ASTNode[] selectedNodes) { 432 HashMap writtenNames= new HashMap (); 433 WrittenNamesFinder finder= new WrittenNamesFinder(writtenNames); 434 compilationUnit.accept(finder); 435 List ops= new ArrayList (); 436 VariableDeclarationFinder visitor= new VariableDeclarationFinder(true, true, true, compilationUnit, ops, writtenNames); 437 if (selectedNodes.length == 1) { 438 if (selectedNodes[0] instanceof SimpleName) { 439 selectedNodes[0]= selectedNodes[0].getParent(); 440 } 441 selectedNodes[0].accept(visitor); 442 } else { 443 for (int i= 0; i < selectedNodes.length; i++) { 444 ASTNode selectedNode= selectedNodes[i]; 445 selectedNode.accept(visitor); 446 } 447 } 448 if (ops.size() == 0) 449 return null; 450 451 IFixRewriteOperation[] result= (IFixRewriteOperation[])ops.toArray(new IFixRewriteOperation[ops.size()]); 452 String label; 453 if (result.length == 1) { 454 label= FixMessages.VariableDeclarationFix_changeModifierOfUnknownToFinal_description; 455 } else { 456 label= FixMessages.VariableDeclarationFix_ChangeMidifiersToFinalWherPossible_description; 457 } 458 return new VariableDeclarationFix(label, compilationUnit, result); 459 } 460 461 public static IFix createCleanUp(CompilationUnit compilationUnit, 462 boolean addFinalFields, boolean addFinalParameters, boolean addFinalLocals) { 463 464 if (!addFinalFields && !addFinalParameters && !addFinalLocals) 465 return null; 466 467 HashMap writtenNames= new HashMap (); 468 WrittenNamesFinder finder= new WrittenNamesFinder(writtenNames); 469 compilationUnit.accept(finder); 470 471 List operations= new ArrayList (); 472 VariableDeclarationFinder visitor= new VariableDeclarationFinder(addFinalFields, addFinalParameters, addFinalLocals, compilationUnit, operations, writtenNames); 473 compilationUnit.accept(visitor); 474 475 if (operations.isEmpty()) 476 return null; 477 478 return new VariableDeclarationFix(FixMessages.VariableDeclarationFix_add_final_change_name, compilationUnit, (IFixRewriteOperation[])operations.toArray(new IFixRewriteOperation[operations.size()])); 479 } 480 481 private static ModifierChangeOperation createAddFinalOperation(SimpleName name, CompilationUnit compilationUnit, ASTNode decl) { 482 if (decl == null) 483 return null; 484 485 IBinding binding= name.resolveBinding(); 486 if (!canAddFinal(binding, name, decl)) 487 return null; 488 489 if (decl instanceof SingleVariableDeclaration) { 490 return new ModifierChangeOperation(decl, new ArrayList (), Modifier.FINAL, Modifier.VOLATILE); 491 } else if (decl instanceof VariableDeclarationExpression) { 492 return new ModifierChangeOperation(decl, new ArrayList (), Modifier.FINAL, Modifier.VOLATILE); 493 } else if (decl instanceof VariableDeclarationFragment){ 494 VariableDeclarationFragment frag= (VariableDeclarationFragment)decl; 495 decl= decl.getParent(); 496 if (decl instanceof FieldDeclaration || decl instanceof VariableDeclarationStatement) { 497 List list= new ArrayList (); 498 list.add(frag); 499 return new ModifierChangeOperation(decl, list, Modifier.FINAL, Modifier.VOLATILE); 500 } else if (decl instanceof VariableDeclarationExpression) { 501 return new ModifierChangeOperation(decl, new ArrayList (), Modifier.FINAL, Modifier.VOLATILE); 502 } 503 } 504 505 return null; 506 } 507 508 private static boolean canAddFinal(IBinding binding, SimpleName name, ASTNode declNode) { 509 if (!(binding instanceof IVariableBinding)) 510 return false; 511 512 IVariableBinding varbinding= (IVariableBinding)binding; 513 if (Modifier.isFinal(varbinding.getModifiers())) 514 return false; 515 516 ASTNode parent= ASTNodes.getParent(declNode, VariableDeclarationExpression.class); 517 if (parent != null && ((VariableDeclarationExpression)parent).fragments().size() > 1) 518 return false; 519 520 if (varbinding.isField() && !Modifier.isPrivate(varbinding.getModifiers())) 521 return false; 522 523 if (varbinding.isParameter()) { 524 ASTNode varDecl= declNode.getParent(); 525 if (varDecl instanceof MethodDeclaration) { 526 MethodDeclaration declaration= (MethodDeclaration)varDecl; 527 if (declaration.getBody() == null) 528 return false; 529 } 530 } 531 532 return true; 533 } 534 535 protected VariableDeclarationFix(String name, CompilationUnit compilationUnit, IFixRewriteOperation[] fixRewriteOperations) { 536 super(name, compilationUnit, fixRewriteOperations); 537 } 538 539 } 540 | Popular Tags |