1 11 12 package org.eclipse.jdt.internal.ui.text.correction; 13 14 import java.util.ArrayList ; 15 import java.util.HashSet ; 16 import java.util.List ; 17 18 import org.eclipse.core.runtime.Assert; 19 import org.eclipse.core.runtime.CoreException; 20 21 import org.eclipse.swt.graphics.Image; 22 23 import org.eclipse.jdt.core.ICompilationUnit; 24 import org.eclipse.jdt.core.dom.AST; 25 import org.eclipse.jdt.core.dom.ASTNode; 26 import org.eclipse.jdt.core.dom.CompilationUnit; 27 import org.eclipse.jdt.core.dom.IBinding; 28 import org.eclipse.jdt.core.dom.IMethodBinding; 29 import org.eclipse.jdt.core.dom.ITypeBinding; 30 import org.eclipse.jdt.core.dom.IVariableBinding; 31 import org.eclipse.jdt.core.dom.Javadoc; 32 import org.eclipse.jdt.core.dom.MethodDeclaration; 33 import org.eclipse.jdt.core.dom.Name; 34 import org.eclipse.jdt.core.dom.SimpleName; 35 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 36 import org.eclipse.jdt.core.dom.TagElement; 37 import org.eclipse.jdt.core.dom.TextElement; 38 import org.eclipse.jdt.core.dom.Type; 39 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 40 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; 41 import org.eclipse.jdt.core.dom.rewrite.ListRewrite; 42 43 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; 44 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; 45 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 46 import org.eclipse.jdt.internal.corext.dom.Bindings; 47 import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder; 48 import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer; 49 50 public class ChangeMethodSignatureProposal extends LinkedCorrectionProposal { 51 52 public static interface ChangeDescription { 53 } 54 55 public static class SwapDescription implements ChangeDescription { 56 final int index; 57 public SwapDescription(int index) { 58 this.index= index; 59 } 60 } 61 62 public static class RemoveDescription implements ChangeDescription { 63 } 64 65 static class ModifyDescription implements ChangeDescription { 66 public final String name; 67 public final ITypeBinding type; 68 Type resultingParamType; 69 SimpleName[] resultingParamName; 70 SimpleName resultingTagArg; 71 72 private ModifyDescription(ITypeBinding type, String name) { 73 this.type= type; 74 this.name= name; 75 } 76 } 77 78 public static class EditDescription extends ModifyDescription { 79 String orginalName; 80 81 public EditDescription(ITypeBinding type, String name) { 82 super(type, name); 83 } 84 } 85 86 public static class InsertDescription extends ModifyDescription { 87 public InsertDescription(ITypeBinding type, String name) { 88 super(type, name); 89 } 90 } 91 92 private ASTNode fInvocationNode; 93 private IMethodBinding fSenderBinding; 94 private ChangeDescription[] fParameterChanges; 95 private ChangeDescription[] fExceptionChanges; 96 97 public ChangeMethodSignatureProposal(String label, ICompilationUnit targetCU, ASTNode invocationNode, IMethodBinding binding, ChangeDescription[] paramChanges, ChangeDescription[] exceptionChanges, int relevance, Image image) { 98 super(label, targetCU, null, relevance, image); 99 100 Assert.isTrue(binding != null && Bindings.isDeclarationBinding(binding)); 101 102 fInvocationNode= invocationNode; 103 fSenderBinding= binding; 104 fParameterChanges= paramChanges; 105 fExceptionChanges= exceptionChanges; 106 } 107 108 protected ASTRewrite getRewrite() throws CoreException { 109 CompilationUnit astRoot= (CompilationUnit) fInvocationNode.getRoot(); 110 ASTNode methodDecl= astRoot.findDeclaringNode(fSenderBinding); 111 ASTNode newMethodDecl= null; 112 boolean isInDifferentCU; 113 if (methodDecl != null) { 114 isInDifferentCU= false; 115 newMethodDecl= methodDecl; 116 } else { 117 isInDifferentCU= true; 118 astRoot= ASTResolving.createQuickFixAST(getCompilationUnit(), null); 119 newMethodDecl= astRoot.findDeclaringNode(fSenderBinding.getKey()); 120 } 121 createImportRewrite(astRoot); 122 123 if (newMethodDecl instanceof MethodDeclaration) { 124 MethodDeclaration decl= (MethodDeclaration) newMethodDecl; 125 126 ASTRewrite rewrite= ASTRewrite.create(astRoot.getAST()); 127 if (fParameterChanges != null) { 128 modifyParameters(rewrite, decl, isInDifferentCU); 129 } 130 if (fExceptionChanges != null) { 131 modifyExceptions(rewrite, decl); 132 } 133 return rewrite; 134 } 135 return null; 136 } 137 138 private void modifyParameters(ASTRewrite rewrite, MethodDeclaration methodDecl, boolean isInDifferentCU) throws CoreException { 139 AST ast= methodDecl.getAST(); 140 141 ArrayList usedNames= new ArrayList (); 142 boolean hasCreatedVariables= false; 143 144 IVariableBinding[] declaredFields= fSenderBinding.getDeclaringClass().getDeclaredFields(); 145 for (int i= 0; i < declaredFields.length; i++) { usedNames.add(declaredFields[i].getName()); 147 } 148 149 ImportRewrite imports= getImportRewrite(); 150 ListRewrite listRewrite= rewrite.getListRewrite(methodDecl, MethodDeclaration.PARAMETERS_PROPERTY); 151 152 List parameters= methodDecl.parameters(); int k= 0; 155 for (int i= 0; i < fParameterChanges.length; i++) { 156 ChangeDescription curr= fParameterChanges[i]; 157 158 if (curr == null) { 159 SingleVariableDeclaration oldParam= (SingleVariableDeclaration) parameters.get(k); 160 usedNames.add(oldParam.getName().getIdentifier()); 161 k++; 162 } else if (curr instanceof InsertDescription) { 163 InsertDescription desc= (InsertDescription) curr; 164 SingleVariableDeclaration newNode= ast.newSingleVariableDeclaration(); 165 newNode.setType(imports.addImport(desc.type, ast)); 166 newNode.setName(ast.newSimpleName("x")); 168 desc.resultingParamName= new SimpleName[] {newNode.getName()}; 170 desc.resultingParamType= newNode.getType(); 171 hasCreatedVariables= true; 172 173 listRewrite.insertAt(newNode, i, null); 174 175 Javadoc javadoc= methodDecl.getJavadoc(); 176 if (javadoc != null) { 177 TagElement newTagElement= ast.newTagElement(); 178 newTagElement.setTagName(TagElement.TAG_PARAM); 179 SimpleName arg= ast.newSimpleName("x"); newTagElement.fragments().add(arg); 181 insertTabStop(rewrite, newTagElement.fragments(), "param_tagcomment" + i); insertParamTag(rewrite.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY), parameters, k, newTagElement); 183 desc.resultingTagArg= arg; } else { 185 desc.resultingTagArg= null; 186 } 187 } else if (curr instanceof RemoveDescription) { 188 SingleVariableDeclaration decl= (SingleVariableDeclaration) parameters.get(k); 189 190 listRewrite.remove(decl, null); 191 k++; 192 193 TagElement tagNode= findParamTag(methodDecl, decl); 194 if (tagNode != null) { 195 rewrite.remove(tagNode, null); 196 } 197 } else if (curr instanceof EditDescription) { 198 EditDescription desc= (EditDescription) curr; 199 200 ITypeBinding newTypeBinding= desc.type; 201 SingleVariableDeclaration decl= (SingleVariableDeclaration) parameters.get(k); 202 203 if (k == parameters.size() - 1 && i == fParameterChanges.length - 1 && decl.isVarargs() && newTypeBinding.isArray()) { 204 newTypeBinding= newTypeBinding.getElementType(); } else { 206 rewrite.set(decl, SingleVariableDeclaration.VARARGS_PROPERTY, Boolean.FALSE, null); 207 } 208 209 Type newType= imports.addImport(newTypeBinding, ast); 210 rewrite.replace(decl.getType(), newType, null); 211 rewrite.set(decl, SingleVariableDeclaration.EXTRA_DIMENSIONS_PROPERTY, new Integer (0), null); 212 213 IBinding binding= decl.getName().resolveBinding(); 214 if (binding != null) { 215 SimpleName[] names= LinkedNodeFinder.findByBinding(decl.getRoot(), binding); 216 SimpleName[] newNames= new SimpleName[names.length]; 217 for (int j= 0; j < names.length; j++) { 218 SimpleName newName= ast.newSimpleName("x"); newNames[j]= newName; 220 rewrite.replace(names[j], newName, null); 221 222 } 223 desc.resultingParamName= newNames; 224 } else { 225 SimpleName newName= ast.newSimpleName("x"); rewrite.replace(decl.getName(), newName, null); 227 desc.resultingParamName= new SimpleName[] {newName}; 229 } 230 231 desc.resultingParamType= newType; 232 desc.orginalName= decl.getName().getIdentifier(); 233 hasCreatedVariables= true; 234 235 k++; 236 237 TagElement tagNode= findParamTag(methodDecl, decl); 238 if (tagNode != null) { 239 List fragments= tagNode.fragments(); 240 if (!fragments.isEmpty()) { 241 SimpleName arg= ast.newSimpleName("x"); rewrite.replace((ASTNode) fragments.get(0), arg, null); 243 desc.resultingTagArg= arg; 244 } 245 } 246 247 } else if (curr instanceof SwapDescription) { 248 SingleVariableDeclaration decl1= (SingleVariableDeclaration) parameters.get(k); 249 SingleVariableDeclaration decl2= (SingleVariableDeclaration) parameters.get(((SwapDescription) curr).index); 250 251 rewrite.replace(decl1, rewrite.createCopyTarget(decl2), null); 252 rewrite.replace(decl2, rewrite.createCopyTarget(decl1), null); 253 254 usedNames.add(decl1.getName().getIdentifier()); 255 k++; 256 257 TagElement tagNode1= findParamTag(methodDecl, decl1); 258 TagElement tagNode2= findParamTag(methodDecl, decl2); 259 if (tagNode1 != null && tagNode2 != null) { 260 rewrite.replace(tagNode1, rewrite.createCopyTarget(tagNode2), null); 261 rewrite.replace(tagNode2, rewrite.createCopyTarget(tagNode1), null); 262 } 263 } 264 } 265 if (!hasCreatedVariables) { 266 return; 267 } 268 269 if (methodDecl.getBody() != null) { 270 CompilationUnit root= (CompilationUnit) methodDecl.getRoot(); 272 IBinding[] bindings= (new ScopeAnalyzer(root)).getDeclarationsAfter(methodDecl.getBody().getStartPosition(), ScopeAnalyzer.VARIABLES); 273 for (int i= 0; i < bindings.length; i++) { 274 usedNames.add(bindings[i].getName()); 275 } 276 } 277 278 fixupNames(rewrite, usedNames, methodDecl, isInDifferentCU); 279 } 280 281 private void fixupNames(ASTRewrite rewrite, ArrayList usedNames, MethodDeclaration methodDecl, boolean isInDifferentCU) { 282 AST ast= rewrite.getAST(); 283 for (int i= 0; i < fParameterChanges.length; i++) { 285 ChangeDescription curr= fParameterChanges[i]; 286 if (curr instanceof ModifyDescription) { 287 ModifyDescription desc= (ModifyDescription) curr; 288 289 String typeKey= getParamTypeGroupId(i); 290 String nameKey= getParamNameGroupId(i); 291 292 String favourite= null; 294 String [] excludedNames= (String []) usedNames.toArray(new String [usedNames.size()]); 295 296 String suggestedName= desc.name; 297 if (suggestedName != null) { 298 favourite= StubUtility.suggestArgumentName(getCompilationUnit().getJavaProject(), suggestedName, excludedNames); 299 addLinkedPositionProposal(nameKey, favourite, null); 300 } 301 302 if (desc instanceof EditDescription) { 303 addLinkedPositionProposal(nameKey, ((EditDescription)desc).orginalName, null); 304 } 305 306 Type type= desc.resultingParamType; 307 String [] suggestedNames= StubUtility.getArgumentNameSuggestions(getCompilationUnit().getJavaProject(), type, excludedNames); 308 for (int k= 0; k < suggestedNames.length; k++) { 309 addLinkedPositionProposal(nameKey, suggestedNames[k], null); 310 } 311 if (favourite == null) { 312 favourite= suggestedNames[0]; 313 } 314 usedNames.add(favourite); 315 316 SimpleName[] names= desc.resultingParamName; 317 for (int j= 0; j < names.length; j++) { 318 names[j].setIdentifier(favourite); 319 addLinkedPosition(rewrite.track(names[j]), false, nameKey); 320 } 321 322 addLinkedPosition(rewrite.track(desc.resultingParamType), true, typeKey); 323 324 ITypeBinding[] bindings= ASTResolving.getRelaxingTypes(ast, desc.type); 326 for (int k= 0; k < bindings.length; k++) { 327 addLinkedPositionProposal(typeKey, bindings[k]); 328 } 329 330 SimpleName tagArg= desc.resultingTagArg; 331 if (tagArg != null) { 332 tagArg.setIdentifier(favourite); 333 addLinkedPosition(rewrite.track(tagArg), false, nameKey); 334 } 335 } 336 } 337 } 338 339 private TagElement findParamTag(MethodDeclaration decl, SingleVariableDeclaration param) { 340 Javadoc javadoc= decl.getJavadoc(); 341 if (javadoc != null) { 342 return JavadocTagsSubProcessor.findParamTag(javadoc, param.getName().getIdentifier()); 343 } 344 return null; 345 } 346 347 private TagElement insertParamTag(ListRewrite tagRewriter, List parameters, int currentIndex, TagElement newTagElement) { 348 HashSet previousNames= new HashSet (); 349 for (int n = 0; n < currentIndex; n++) { 350 SingleVariableDeclaration var= (SingleVariableDeclaration) parameters.get(n); 351 previousNames.add(var.getName().getIdentifier()); 352 } 353 354 JavadocTagsSubProcessor.insertTag(tagRewriter, newTagElement, previousNames); 355 return newTagElement; 356 } 357 358 private void modifyExceptions(ASTRewrite rewrite, MethodDeclaration methodDecl) throws CoreException { 359 AST ast= methodDecl.getAST(); 360 361 ImportRewrite imports= getImportRewrite(); 362 ListRewrite listRewrite= rewrite.getListRewrite(methodDecl, MethodDeclaration.THROWN_EXCEPTIONS_PROPERTY); 363 364 List exceptions= methodDecl.thrownExceptions(); int k= 0; 367 for (int i= 0; i < fExceptionChanges.length; i++) { 368 ChangeDescription curr= fExceptionChanges[i]; 369 370 if (curr == null) { 371 k++; 372 } else if (curr instanceof InsertDescription) { 373 InsertDescription desc= (InsertDescription) curr; 374 String type= imports.addImport(desc.type); 375 ASTNode newNode= ASTNodeFactory.newName(ast, type); 376 377 listRewrite.insertAt(newNode, i, null); 378 379 String key= getExceptionTypeGroupId(i); 380 addLinkedPosition(rewrite.track(newNode), false, key); 381 382 Javadoc javadoc= methodDecl.getJavadoc(); 383 if (javadoc != null) { 384 TagElement newTagElement= ast.newTagElement(); 385 newTagElement.setTagName(TagElement.TAG_THROWS); 386 ASTNode newRef= ASTNodeFactory.newName(ast, type); 387 newTagElement.fragments().add(newRef); 388 insertTabStop(rewrite, newTagElement.fragments(), "throws_tagcomment" + i); insertThrowsTag(rewrite.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY), exceptions, k, newTagElement); 390 391 addLinkedPosition(rewrite.track(newRef), false, key); 392 } 393 394 } else if (curr instanceof RemoveDescription) { 395 Name node= (Name) exceptions.get(k); 396 397 listRewrite.remove(node, null); 398 k++; 399 400 TagElement tagNode= findThrowsTag(methodDecl, node); 401 if (tagNode != null) { 402 rewrite.remove(tagNode, null); 403 } 404 } else if (curr instanceof EditDescription) { 405 EditDescription desc= (EditDescription) curr; 406 407 Name oldNode= (Name) exceptions.get(k); 408 409 String type= imports.addImport(desc.type); 410 ASTNode newNode= ASTNodeFactory.newName(ast, type); 411 412 listRewrite.replace(oldNode, newNode, null); 413 String key= getExceptionTypeGroupId(i); 414 addLinkedPosition(rewrite.track(newNode), false, key); 415 416 k++; 417 418 TagElement tagNode= findThrowsTag(methodDecl, oldNode); 419 if (tagNode != null) { 420 ASTNode newRef= ASTNodeFactory.newName(ast, type); 421 rewrite.replace((ASTNode) tagNode.fragments().get(0), newRef, null); 422 addLinkedPosition(rewrite.track(newRef), false, key); 423 } 424 425 } else if (curr instanceof SwapDescription) { 426 Name decl1= (Name) exceptions.get(k); 427 Name decl2= (Name) exceptions.get(((SwapDescription) curr).index); 428 429 rewrite.replace(decl1, rewrite.createCopyTarget(decl2), null); 430 rewrite.replace(decl2, rewrite.createCopyTarget(decl1), null); 431 432 k++; 433 434 TagElement tagNode1= findThrowsTag(methodDecl, decl1); 435 TagElement tagNode2= findThrowsTag(methodDecl, decl2); 436 if (tagNode1 != null && tagNode2 != null) { 437 rewrite.replace(tagNode1, rewrite.createCopyTarget(tagNode2), null); 438 rewrite.replace(tagNode2, rewrite.createCopyTarget(tagNode1), null); 439 } 440 } 441 } 442 } 443 444 private void insertTabStop(ASTRewrite rewriter, List fragments, String linkedName) { 445 TextElement textElement= rewriter.getAST().newTextElement(); 446 textElement.setText(""); fragments.add(textElement); 448 addLinkedPosition(rewriter.track(textElement), false, linkedName); 449 } 450 451 private TagElement findThrowsTag(MethodDeclaration decl, Name exception) { 452 Javadoc javadoc= decl.getJavadoc(); 453 if (javadoc != null) { 454 String name= ASTNodes.getSimpleNameIdentifier(exception); 455 return JavadocTagsSubProcessor.findThrowsTag(javadoc, name); 456 } 457 return null; 458 } 459 460 private TagElement insertThrowsTag(ListRewrite tagRewriter, List exceptions, int currentIndex, TagElement newTagElement) { 461 HashSet previousNames= new HashSet (); 462 for (int n = 0; n < currentIndex; n++) { 463 Name curr= (Name) exceptions.get(n); 464 previousNames.add(ASTNodes.getSimpleNameIdentifier(curr)); 465 } 466 467 JavadocTagsSubProcessor.insertTag(tagRewriter, newTagElement, previousNames); 468 return newTagElement; 469 } 470 471 472 public String getParamNameGroupId(int idx) { 473 return "param_name_" + idx; } 475 476 public String getParamTypeGroupId(int idx) { 477 return "param_type_" + idx; } 479 480 public String getExceptionTypeGroupId(int idx) { 481 return "exc_type_" + idx; } 483 484 } 485 | Popular Tags |