1 11 12 package org.eclipse.jdt.internal.ui.text.correction; 13 14 import java.util.Arrays ; 15 import java.util.Comparator ; 16 import java.util.HashSet ; 17 import java.util.Iterator ; 18 import java.util.List ; 19 20 import org.eclipse.core.runtime.Assert; 21 import org.eclipse.core.runtime.CoreException; 22 23 import org.eclipse.swt.graphics.Image; 24 25 import org.eclipse.jdt.core.ICompilationUnit; 26 import org.eclipse.jdt.core.dom.AST; 27 import org.eclipse.jdt.core.dom.ASTNode; 28 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; 29 import org.eclipse.jdt.core.dom.Assignment; 30 import org.eclipse.jdt.core.dom.Block; 31 import org.eclipse.jdt.core.dom.BodyDeclaration; 32 import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; 33 import org.eclipse.jdt.core.dom.CompilationUnit; 34 import org.eclipse.jdt.core.dom.EnumConstantDeclaration; 35 import org.eclipse.jdt.core.dom.EnumDeclaration; 36 import org.eclipse.jdt.core.dom.Expression; 37 import org.eclipse.jdt.core.dom.ExpressionStatement; 38 import org.eclipse.jdt.core.dom.FieldDeclaration; 39 import org.eclipse.jdt.core.dom.ForStatement; 40 import org.eclipse.jdt.core.dom.IBinding; 41 import org.eclipse.jdt.core.dom.ITypeBinding; 42 import org.eclipse.jdt.core.dom.Initializer; 43 import org.eclipse.jdt.core.dom.Javadoc; 44 import org.eclipse.jdt.core.dom.MethodDeclaration; 45 import org.eclipse.jdt.core.dom.MethodInvocation; 46 import org.eclipse.jdt.core.dom.Modifier; 47 import org.eclipse.jdt.core.dom.QualifiedName; 48 import org.eclipse.jdt.core.dom.SimpleName; 49 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 50 import org.eclipse.jdt.core.dom.Statement; 51 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; 52 import org.eclipse.jdt.core.dom.TagElement; 53 import org.eclipse.jdt.core.dom.TextElement; 54 import org.eclipse.jdt.core.dom.Type; 55 import org.eclipse.jdt.core.dom.TypeDeclaration; 56 import org.eclipse.jdt.core.dom.VariableDeclarationExpression; 57 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 58 import org.eclipse.jdt.core.dom.VariableDeclarationStatement; 59 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 60 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; 61 import org.eclipse.jdt.core.dom.rewrite.ListRewrite; 62 63 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; 64 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 65 import org.eclipse.jdt.internal.corext.dom.Bindings; 66 import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder; 67 68 public class NewVariableCompletionProposal extends LinkedCorrectionProposal { 69 70 public static final int LOCAL= 1; 71 public static final int FIELD= 2; 72 public static final int PARAM= 3; 73 74 public static final int CONST_FIELD= 4; 75 public static final int ENUM_CONST= 5; 76 77 private static final String KEY_NAME= "name"; private static final String KEY_TYPE= "type"; private static final String KEY_INITIALIZER= "initializer"; 81 final private int fVariableKind; 82 final private SimpleName fOriginalNode; 83 final private ITypeBinding fSenderBinding; 84 85 public NewVariableCompletionProposal(String label, ICompilationUnit cu, int variableKind, SimpleName node, ITypeBinding senderBinding, int relevance, Image image) { 86 super(label, cu, null, relevance, image); 87 if (senderBinding == null) { 88 Assert.isTrue(variableKind == PARAM || variableKind == LOCAL); 89 } else { 90 Assert.isTrue(Bindings.isDeclarationBinding(senderBinding)); 91 } 92 93 fVariableKind= variableKind; 94 fOriginalNode= node; 95 fSenderBinding= senderBinding; 96 } 97 98 protected ASTRewrite getRewrite() throws CoreException { 99 CompilationUnit cu= ASTResolving.findParentCompilationUnit(fOriginalNode); 100 switch (fVariableKind) { 101 case PARAM: 102 return doAddParam(cu); 103 case FIELD: 104 case CONST_FIELD: 105 return doAddField(cu); 106 case LOCAL: 107 return doAddLocal(cu); 108 case ENUM_CONST: 109 return doAddEnumConst(cu); 110 default: 111 throw new IllegalArgumentException ("Unsupported variable kind: " + fVariableKind); } 113 } 114 115 private ASTRewrite doAddParam(CompilationUnit cu) throws CoreException { 116 AST ast= cu.getAST(); 117 SimpleName node= fOriginalNode; 118 119 BodyDeclaration decl= ASTResolving.findParentBodyDeclaration(node); 120 if (decl instanceof MethodDeclaration) { 121 MethodDeclaration methodDeclaration= (MethodDeclaration) decl; 122 123 ASTRewrite rewrite= ASTRewrite.create(ast); 124 125 ImportRewrite imports= createImportRewrite((CompilationUnit) decl.getRoot()); 126 127 SingleVariableDeclaration newDecl= ast.newSingleVariableDeclaration(); 128 newDecl.setType(evaluateVariableType(ast, imports, methodDeclaration.resolveBinding())); 129 newDecl.setName(ast.newSimpleName(node.getIdentifier())); 130 131 ListRewrite listRewriter= rewrite.getListRewrite(decl, MethodDeclaration.PARAMETERS_PROPERTY); 132 listRewriter.insertLast(newDecl, null); 133 134 addLinkedPosition(rewrite.track(newDecl.getType()), false, KEY_TYPE); 135 addLinkedPosition(rewrite.track(node), true, KEY_NAME); 136 addLinkedPosition(rewrite.track(newDecl.getName()), false, KEY_NAME); 137 138 Javadoc javadoc= methodDeclaration.getJavadoc(); 140 if (javadoc != null) { 141 HashSet leadingNames= new HashSet (); 142 for (Iterator iter= methodDeclaration.parameters().iterator(); iter.hasNext();) { 143 SingleVariableDeclaration curr= (SingleVariableDeclaration) iter.next(); 144 leadingNames.add(curr.getName().getIdentifier()); 145 } 146 SimpleName newTagRef= ast.newSimpleName(node.getIdentifier()); 147 148 TagElement newTagElement= ast.newTagElement(); 149 newTagElement.setTagName(TagElement.TAG_PARAM); 150 newTagElement.fragments().add(newTagRef); 151 TextElement commentStart= ast.newTextElement(); 152 newTagElement.fragments().add(commentStart); 153 154 addLinkedPosition(rewrite.track(newTagRef), true, KEY_NAME); 155 addLinkedPosition(rewrite.track(commentStart), false, "comment_start"); 157 ListRewrite tagsRewriter= rewrite.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY); 158 JavadocTagsSubProcessor.insertTag(tagsRewriter, newTagElement, leadingNames); 159 } 160 161 return rewrite; 162 } 163 return null; 164 } 165 166 private boolean isAssigned(Statement statement, SimpleName name) { 167 if (statement instanceof ExpressionStatement) { 168 ExpressionStatement exstat= (ExpressionStatement) statement; 169 if (exstat.getExpression() instanceof Assignment) { 170 Assignment assignment= (Assignment) exstat.getExpression(); 171 return assignment.getLeftHandSide() == name; 172 } 173 } 174 return false; 175 } 176 177 private boolean isForStatementInit(Statement statement, SimpleName name) { 178 if (statement instanceof ForStatement) { 179 ForStatement forStatement= (ForStatement) statement; 180 List list = forStatement.initializers(); 181 if (list.size() == 1 && list.get(0) instanceof Assignment) { 182 Assignment assignment= (Assignment) list.get(0); 183 return assignment.getLeftHandSide() == name; 184 } 185 } 186 return false; 187 } 188 189 190 private ASTRewrite doAddLocal(CompilationUnit cu) throws CoreException { 191 AST ast= cu.getAST(); 192 193 Block body; 194 BodyDeclaration decl= ASTResolving.findParentBodyDeclaration(fOriginalNode); 195 IBinding targetContext= null; 196 if (decl instanceof MethodDeclaration) { 197 body= (((MethodDeclaration) decl).getBody()); 198 targetContext= ((MethodDeclaration) decl).resolveBinding(); 199 } else if (decl instanceof Initializer) { 200 body= (((Initializer) decl).getBody()); 201 targetContext= Bindings.getBindingOfParentType(decl); 202 } else { 203 return null; 204 } 205 ASTRewrite rewrite= ASTRewrite.create(ast); 206 207 ImportRewrite imports= createImportRewrite((CompilationUnit) decl.getRoot()); 208 209 SimpleName[] names= getAllReferences(body); 210 ASTNode dominant= getDominantNode(names); 211 212 Statement dominantStatement= ASTResolving.findParentStatement(dominant); 213 if (ASTNodes.isControlStatementBody(dominantStatement.getLocationInParent())) { 214 dominantStatement= (Statement) dominantStatement.getParent(); 215 } 216 217 SimpleName node= names[0]; 218 219 if (isAssigned(dominantStatement, node)) { 220 Assignment assignment= (Assignment) node.getParent(); 222 223 VariableDeclarationFragment newDeclFrag= ast.newVariableDeclarationFragment(); 226 VariableDeclarationExpression newDecl= ast.newVariableDeclarationExpression(newDeclFrag); 227 newDecl.setType(evaluateVariableType(ast, imports, targetContext)); 228 229 Expression placeholder= (Expression) rewrite.createCopyTarget(assignment.getRightHandSide()); 230 newDeclFrag.setInitializer(placeholder); 231 newDeclFrag.setName(ast.newSimpleName(node.getIdentifier())); 232 rewrite.replace(assignment, newDecl, null); 233 234 addLinkedPosition(rewrite.track(newDecl.getType()), false, KEY_TYPE); 235 addLinkedPosition(rewrite.track(newDeclFrag.getName()), true, KEY_NAME); 236 237 setEndPosition(rewrite.track(assignment.getParent())); 238 239 return rewrite; 240 } else if ((dominant != dominantStatement) && isForStatementInit(dominantStatement, node)) { 241 243 Assignment assignment= (Assignment) node.getParent(); 244 245 VariableDeclarationFragment frag= ast.newVariableDeclarationFragment(); 246 VariableDeclarationExpression expression= ast.newVariableDeclarationExpression(frag); 247 frag.setName(ast.newSimpleName(node.getIdentifier())); 248 Expression placeholder= (Expression) rewrite.createCopyTarget(assignment.getRightHandSide()); 249 frag.setInitializer(placeholder); 250 expression.setType(evaluateVariableType(ast, imports, targetContext)); 251 252 rewrite.replace(assignment, expression, null); 253 254 addLinkedPosition(rewrite.track(expression.getType()), false, KEY_TYPE); 255 addLinkedPosition(rewrite.track(frag.getName()), true, KEY_NAME); 256 257 setEndPosition(rewrite.track(expression)); 258 259 return rewrite; 260 } 261 263 VariableDeclarationFragment newDeclFrag= ast.newVariableDeclarationFragment(); 264 VariableDeclarationStatement newDecl= ast.newVariableDeclarationStatement(newDeclFrag); 265 266 newDeclFrag.setName(ast.newSimpleName(node.getIdentifier())); 267 newDecl.setType(evaluateVariableType(ast, imports, targetContext)); 268 270 addLinkedPosition(rewrite.track(newDecl.getType()), false, KEY_TYPE); 271 addLinkedPosition(rewrite.track(node), true, KEY_NAME); 272 addLinkedPosition(rewrite.track(newDeclFrag.getName()), false, KEY_NAME); 273 274 Statement statement= dominantStatement; 275 List list= ASTNodes.getContainingList(statement); 276 while (list == null && statement.getParent() instanceof Statement) { statement= (Statement) statement.getParent(); 278 list= ASTNodes.getContainingList(statement); 279 } 280 if (list != null) { 281 ASTNode parent= statement.getParent(); 282 StructuralPropertyDescriptor childProperty= statement.getLocationInParent(); 283 if (childProperty.isChildListProperty()) { 284 rewrite.getListRewrite(parent, (ChildListPropertyDescriptor) childProperty).insertBefore(newDecl, statement, null); 285 return rewrite; 286 } else { 287 return null; 288 } 289 } 290 return rewrite; 291 } 292 293 private SimpleName[] getAllReferences(Block body) { 294 SimpleName[] names= LinkedNodeFinder.findByProblems(body, fOriginalNode); 295 if (names == null) { 296 return new SimpleName[] { fOriginalNode }; 297 } 298 if (names.length > 1) { 299 Arrays.sort(names, new Comparator () { 300 public int compare(Object o1, Object o2) { 301 return ((SimpleName) o1).getStartPosition() - ((SimpleName) o2).getStartPosition(); 302 } 303 }); 304 } 305 return names; 306 } 307 308 309 private ASTNode getDominantNode(SimpleName[] names) { 310 ASTNode dominator= names[0]; for (int i= 1; i < names.length; i++) { 312 ASTNode curr= names[i]; if (curr != dominator) { 314 ASTNode parent= getCommonParent(curr, dominator); 315 316 if (curr.getStartPosition() < dominator.getStartPosition()) { 317 dominator= curr; 318 } 319 while (dominator.getParent() != parent) { 320 dominator= dominator.getParent(); 321 } 322 } 323 } 324 int parentKind= dominator.getParent().getNodeType(); 325 if (parentKind != ASTNode.BLOCK && parentKind != ASTNode.FOR_STATEMENT) { 326 return dominator.getParent(); 327 } 328 return dominator; 329 } 330 331 private ASTNode getCommonParent(ASTNode node1, ASTNode node2) { 332 ASTNode parent= node1.getParent(); 333 while (parent != null && !ASTNodes.isParent(node2, parent)) { 334 parent= parent.getParent(); 335 } 336 return parent; 337 } 338 339 private ASTRewrite doAddField(CompilationUnit astRoot) throws CoreException { 340 SimpleName node= fOriginalNode; 341 boolean isInDifferentCU= false; 342 343 ASTNode newTypeDecl= astRoot.findDeclaringNode(fSenderBinding); 344 if (newTypeDecl == null) { 345 astRoot= ASTResolving.createQuickFixAST(getCompilationUnit(), null); 346 newTypeDecl= astRoot.findDeclaringNode(fSenderBinding.getKey()); 347 isInDifferentCU= true; 348 } 349 ImportRewrite imports= createImportRewrite(astRoot); 350 351 if (newTypeDecl != null) { 352 AST ast= newTypeDecl.getAST(); 353 354 ASTRewrite rewrite= ASTRewrite.create(ast); 355 356 VariableDeclarationFragment fragment= ast.newVariableDeclarationFragment(); 357 fragment.setName(ast.newSimpleName(node.getIdentifier())); 358 359 Type type= evaluateVariableType(ast, imports, fSenderBinding); 360 361 FieldDeclaration newDecl= ast.newFieldDeclaration(fragment); 362 newDecl.setType(type); 363 newDecl.modifiers().addAll(ASTNodeFactory.newModifiers(ast, evaluateFieldModifiers(newTypeDecl))); 364 365 if (fSenderBinding.isInterface() || fVariableKind == CONST_FIELD) { 366 fragment.setInitializer(ASTNodeFactory.newDefaultExpression(ast, type, 0)); 367 } 368 369 ChildListPropertyDescriptor property= ASTNodes.getBodyDeclarationsProperty(newTypeDecl); 370 List decls= (List ) newTypeDecl.getStructuralProperty(property); 371 372 int maxOffset= isInDifferentCU ? -1 : node.getStartPosition(); 373 374 int insertIndex= findFieldInsertIndex(decls, newDecl, maxOffset); 375 376 ListRewrite listRewriter= rewrite.getListRewrite(newTypeDecl, property); 377 listRewriter.insertAt(newDecl, insertIndex, null); 378 379 ModifierCorrectionSubProcessor.installLinkedVisibilityProposals(getLinkedProposalModel(), rewrite, newDecl.modifiers(), fSenderBinding.isInterface()); 380 381 addLinkedPosition(rewrite.track(newDecl.getType()), false, KEY_TYPE); 382 if (!isInDifferentCU) { 383 addLinkedPosition(rewrite.track(node), true, KEY_NAME); 384 } 385 addLinkedPosition(rewrite.track(fragment.getName()), false, KEY_NAME); 386 387 if (fragment.getInitializer() != null) { 388 addLinkedPosition(rewrite.track(fragment.getInitializer()), false, KEY_INITIALIZER); 389 } 390 return rewrite; 391 } 392 return null; 393 } 394 395 private int findFieldInsertIndex(List decls, FieldDeclaration newDecl, int maxOffset) { 396 if (maxOffset != -1) { 397 for (int i= decls.size() - 1; i >= 0; i--) { 398 ASTNode curr= (ASTNode) decls.get(i); 399 if (maxOffset > curr.getStartPosition() + curr.getLength()) { 400 return ASTNodes.getInsertionIndex(newDecl, decls.subList(0, i + 1)); 401 } 402 } 403 return 0; 404 } 405 return ASTNodes.getInsertionIndex(newDecl, decls); 406 } 407 408 private Type evaluateVariableType(AST ast, ImportRewrite imports, IBinding targetContext) throws CoreException { 409 if (fOriginalNode.getParent() instanceof MethodInvocation) { 410 MethodInvocation parent= (MethodInvocation) fOriginalNode.getParent(); 411 if (parent.getExpression() == fOriginalNode) { 412 ITypeBinding[] bindings= ASTResolving.getQualifierGuess(fOriginalNode.getRoot(), parent.getName().getIdentifier(), parent.arguments(), targetContext); 414 if (bindings.length > 0) { 415 for (int i= 0; i < bindings.length; i++) { 416 addLinkedPositionProposal(KEY_TYPE, bindings[i]); 417 } 418 return imports.addImport(bindings[0], ast); 419 } 420 } 421 } 422 423 ITypeBinding binding= ASTResolving.guessBindingForReference(fOriginalNode); 424 if (binding != null) { 425 if (binding.isWildcardType()) { 426 binding= ASTResolving.normalizeWildcardType(binding, isVariableAssigned(), ast); 427 if (binding == null) { 428 binding= ast.resolveWellKnownType("java.lang.Object"); } 431 } 432 433 if (isVariableAssigned()) { 434 ITypeBinding[] typeProposals= ASTResolving.getRelaxingTypes(ast, binding); 435 for (int i= 0; i < typeProposals.length; i++) { 436 addLinkedPositionProposal(KEY_TYPE, typeProposals[i]); 437 } 438 } 439 return imports.addImport(binding, ast); 440 } 441 Type type= ASTResolving.guessTypeForReference(ast, fOriginalNode); 443 if (type != null) { 444 return type; 445 } 446 if (fVariableKind == CONST_FIELD) { 447 return ast.newSimpleType(ast.newSimpleName("String")); } 449 return ast.newSimpleType(ast.newSimpleName("Object")); } 451 452 private boolean isVariableAssigned() { 453 ASTNode parent= fOriginalNode.getParent(); 454 return (parent instanceof Assignment) && (fOriginalNode == ((Assignment) parent).getLeftHandSide()); 455 } 456 457 458 private int evaluateFieldModifiers(ASTNode newTypeDecl) { 459 if (fSenderBinding.isAnnotation()) { 460 return 0; 461 } 462 if (fSenderBinding.isInterface()) { 463 FieldDeclaration[] fieldDecls= ((TypeDeclaration) newTypeDecl).getFields(); 465 if (fieldDecls.length > 0) { 466 return fieldDecls[0].getModifiers(); 467 } 468 return 0; 469 } 470 int modifiers= 0; 471 472 if (fVariableKind == CONST_FIELD) { 473 modifiers |= Modifier.FINAL | Modifier.STATIC; 474 } else { 475 ASTNode parent= fOriginalNode.getParent(); 476 if (parent instanceof QualifiedName) { 477 IBinding qualifierBinding= ((QualifiedName)parent).getQualifier().resolveBinding(); 478 if (qualifierBinding instanceof ITypeBinding) { 479 modifiers |= Modifier.STATIC; 480 } 481 } else if (ASTResolving.isInStaticContext(fOriginalNode)) { 482 modifiers |= Modifier.STATIC; 483 } 484 } 485 ASTNode node= ASTResolving.findParentType(fOriginalNode, true); 486 if (newTypeDecl.equals(node)) { 487 modifiers |= Modifier.PRIVATE; 488 } else if (node instanceof AnonymousClassDeclaration) { 489 modifiers |= Modifier.PROTECTED; 490 } else { 491 modifiers |= Modifier.PUBLIC; 492 } 493 494 return modifiers; 495 } 496 497 private ASTRewrite doAddEnumConst(CompilationUnit astRoot) throws CoreException { 498 SimpleName node= fOriginalNode; 499 500 ASTNode newTypeDecl= astRoot.findDeclaringNode(fSenderBinding); 501 if (newTypeDecl == null) { 502 astRoot= ASTResolving.createQuickFixAST(getCompilationUnit(), null); 503 newTypeDecl= astRoot.findDeclaringNode(fSenderBinding.getKey()); 504 } 505 506 if (newTypeDecl != null) { 507 AST ast= newTypeDecl.getAST(); 508 509 ASTRewrite rewrite= ASTRewrite.create(ast); 510 511 EnumConstantDeclaration constDecl= ast.newEnumConstantDeclaration(); 512 constDecl.setName(ast.newSimpleName(node.getIdentifier())); 513 514 ListRewrite listRewriter= rewrite.getListRewrite(newTypeDecl, EnumDeclaration.ENUM_CONSTANTS_PROPERTY); 515 listRewriter.insertLast(constDecl, null); 516 517 addLinkedPosition(rewrite.track(constDecl.getName()), false, KEY_NAME); 518 519 return rewrite; 520 } 521 return null; 522 } 523 524 525 526 530 public int getVariableKind() { 531 return fVariableKind; 532 } 533 534 } 535 | Popular Tags |