1 19 package org.netbeans.modules.java.hints; 20 21 import com.sun.source.tree.ArrayAccessTree; 22 import com.sun.source.tree.AssertTree; 23 import com.sun.source.tree.AssignmentTree; 24 import com.sun.source.tree.BinaryTree; 25 import com.sun.source.tree.ClassTree; 26 import com.sun.source.tree.DoWhileLoopTree; 27 import com.sun.source.tree.EnhancedForLoopTree; 28 import com.sun.source.tree.ForLoopTree; 29 import com.sun.source.tree.IfTree; 30 import com.sun.source.tree.InstanceOfTree; 31 import com.sun.source.tree.MemberSelectTree; 32 import com.sun.source.tree.MethodTree; 33 import com.sun.source.tree.ParenthesizedTree; 34 import com.sun.source.tree.ReturnTree; 35 import com.sun.source.tree.SwitchTree; 36 import com.sun.source.tree.SynchronizedTree; 37 import com.sun.source.tree.ThrowTree; 38 import com.sun.source.tree.Tree; 39 import com.sun.source.tree.Tree.Kind; 40 import com.sun.source.tree.UnaryTree; 41 import com.sun.source.tree.VariableTree; 42 import com.sun.source.tree.WhileLoopTree; 43 import com.sun.source.util.TreePath; 44 import java.io.IOException ; 45 import java.util.ArrayList ; 46 import java.util.Collections ; 47 import java.util.EnumSet ; 48 import java.util.List ; 49 import java.util.Set ; 50 import java.util.logging.Level ; 51 import java.util.logging.Logger ; 52 import javax.lang.model.element.Element; 53 import javax.lang.model.element.ElementKind; 54 import javax.lang.model.element.Modifier; 55 import javax.lang.model.element.ExecutableElement; 56 import javax.lang.model.element.TypeElement; 57 import javax.lang.model.type.ArrayType; 58 import javax.lang.model.type.DeclaredType; 59 import javax.lang.model.type.ExecutableType; 60 import javax.lang.model.type.TypeKind; 61 import javax.lang.model.type.TypeMirror; 62 import org.netbeans.api.java.source.CancellableTask; 63 import org.netbeans.api.java.source.ClasspathInfo; 64 import org.netbeans.api.java.source.CompilationInfo; 65 import org.netbeans.api.java.source.ElementHandle; 66 import org.netbeans.api.java.source.JavaSource; 67 import org.netbeans.api.java.source.JavaSource.Phase; 68 import org.netbeans.api.java.source.SourceUtils; 69 import org.netbeans.api.java.source.TreeMaker; 70 import org.netbeans.api.java.source.TypeMirrorHandle; 71 import org.netbeans.api.java.source.WorkingCopy; 72 import org.netbeans.modules.java.editor.semantic.Utilities; 73 import org.netbeans.modules.java.hints.spi.ErrorRule; 74 import org.netbeans.spi.editor.hints.ChangeInfo; 75 import org.netbeans.spi.editor.hints.Fix; 76 import org.openide.ErrorManager; 77 import org.openide.filesystems.FileObject; 78 79 83 public final class CreateElement implements ErrorRule<Void > { 84 85 86 public CreateElement() { 87 } 88 89 public Set <String > getCodes() { 90 return Collections.singleton("compiler.err.cant.resolve.location"); 91 } 92 93 public List <Fix> run(CompilationInfo info, String diagnosticKey, int offset, TreePath treePath, Data<Void > data) { 94 return analyze(info, offset); 95 } 96 97 static List <Fix> analyze(CompilationInfo info, int offset) { 98 TreePath errorPath = JavaHintsProvider.findUnresolvedElement(info, offset); 99 100 if (errorPath == null) { 101 return Collections.<Fix>emptyList(); 102 } 103 104 TreePath parent = null; 105 TreePath firstClass = null; 106 TreePath firstMethod = null; 107 TreePath firstInitializer = null; 108 109 TreePath path = info.getTreeUtilities().pathFor(offset + 1); 110 while(path != null) { 111 if (parent != null && parent.getLeaf() == errorPath.getLeaf()) 112 parent = path; 113 if (path.getLeaf() == errorPath.getLeaf() && parent == null) 114 parent = path; 115 if (path.getLeaf().getKind() == Kind.CLASS && firstClass == null) 116 firstClass = path; 117 if (path.getLeaf().getKind() == Kind.METHOD && firstMethod == null && firstClass == null) 118 firstMethod = path; 119 if ( path.getLeaf().getKind() == Kind.BLOCK && path.getParentPath().getLeaf().getKind() == Kind.CLASS 121 && firstMethod == null && firstClass == null) 122 firstInitializer = path; 123 path = path.getParentPath(); 124 } 125 126 if (parent == null || parent.getLeaf() == errorPath.getLeaf() || firstClass == null) 127 return Collections.<Fix>emptyList(); 128 129 Element e = info.getTrees().getElement(errorPath); 130 131 if (e == null) { 132 return Collections.<Fix>emptyList(); 133 } 134 135 Set <Modifier> modifiers = EnumSet.noneOf(Modifier.class); 136 String simpleName = e.getSimpleName().toString(); 137 TypeElement source = (TypeElement) info.getTrees().getElement(firstClass); 138 TypeElement target = null; 139 boolean allowLocalVariables = true; 140 141 if (errorPath.getLeaf().getKind() == Kind.MEMBER_SELECT) { 142 TreePath exp = new TreePath(errorPath, ((MemberSelectTree) errorPath.getLeaf()).getExpression()); 143 Element targetElement = info.getTrees().getElement(exp); 144 TypeMirror targetType = info.getTrees().getTypeMirror(exp); 145 146 if (targetElement != null && targetType != null && targetType.getKind() != TypeKind.ERROR) { 147 switch (targetElement.getKind()) { 148 case CLASS: 149 case INTERFACE: 150 case ENUM: 151 case ANNOTATION_TYPE: 152 target = (TypeElement) targetElement; 156 modifiers.add(Modifier.STATIC); 157 break; 158 159 case FIELD: 160 case ENUM_CONSTANT: 161 case LOCAL_VARIABLE: 162 case PARAMETER: 163 case EXCEPTION_PARAMETER: 164 TypeMirror tm = targetElement.asType(); 165 if (tm.getKind() == TypeKind.DECLARED) { 166 target = (TypeElement)((DeclaredType)tm).asElement(); 167 } 168 break; 169 case METHOD: 170 Element el = info.getTypes().asElement(((ExecutableElement) targetElement).getReturnType()); 171 172 if (el != null && (el.getKind().isClass() || el.getKind().isInterface())) { 173 target = (TypeElement) el; 174 } 175 176 break; 177 case CONSTRUCTOR: 178 target = (TypeElement) targetElement.getEnclosingElement(); 179 break; 180 } 182 } 183 184 allowLocalVariables = false; 185 } else { 186 if (errorPath.getLeaf().getKind() == Kind.IDENTIFIER) { 187 target = source; 188 189 if (firstMethod != null) { 190 if (((MethodTree)firstMethod.getLeaf()).getModifiers().getFlags().contains(Modifier.STATIC)) { 191 modifiers.add(Modifier.STATIC); 192 } 193 } else { 194 } 196 } 197 } 198 199 if (target == null) { 200 if (JavaHintsProvider.ERR.isLoggable(ErrorManager.INFORMATIONAL)) { 201 JavaHintsProvider.ERR.log(ErrorManager.INFORMATIONAL, "target=null"); 202 JavaHintsProvider.ERR.log(ErrorManager.INFORMATIONAL, "offset=" + offset); 203 JavaHintsProvider.ERR.log(ErrorManager.INFORMATIONAL, "errorTree=" + errorPath.getLeaf()); 204 } 205 206 return Collections.<Fix>emptyList(); 207 } 208 209 modifiers.addAll(getAccessModifiers(source, target)); 210 211 List <Fix> result = new ArrayList <Fix>(); 212 213 Set <FixTypes> fixTypes = EnumSet.noneOf(FixTypes.class); 214 List <? extends TypeMirror> types = resolveType(fixTypes, info, parent, errorPath.getLeaf(), offset); 215 216 if (types == null || types.isEmpty()) { 217 return Collections.<Fix>emptyList(); 218 } 219 220 TypeMirror type = types.get(0); 222 223 if (type == null || type.getKind() == TypeKind.VOID) { 224 return Collections.<Fix>emptyList(); 225 } 226 227 if (containsErrorsOrTypevarsRecursively(type)) { 229 return Collections.<Fix>emptyList(); 230 } 231 232 if (fixTypes.contains(FixTypes.FIELD)) { 233 result.add(new CreateFieldFix(info, simpleName, modifiers, target, type)); 234 } 235 236 if (allowLocalVariables && (fixTypes.contains(FixTypes.LOCAL) || types.contains(FixTypes.PARAM))) { 237 ExecutableElement ee = null; 238 239 if (firstMethod != null) { 240 ee = (ExecutableElement) info.getTrees().getElement(firstMethod); 241 } 242 243 if ((ee != null) && type != null) { 244 int identifierPos = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), errorPath.getLeaf()); 245 if (ee != null && fixTypes.contains(FixTypes.PARAM)) 246 result.add(new AddParameterOrLocalFix(info, type, simpleName, true, identifierPos)); 247 if (fixTypes.contains(FixTypes.LOCAL)) 248 result.add(new AddParameterOrLocalFix(info, type, simpleName, false, identifierPos)); 249 } 250 } 251 252 return result; 253 } 254 255 public void cancel() { 256 } 258 259 public String getId() { 260 return CreateElement.class.getName(); 261 } 262 263 public String getDisplayName() { 264 return "Create Field Fix"; 265 } 266 267 public String getDescription() { 268 return "Create Field Fix"; 269 } 270 271 private static boolean containsErrorsOrTypevarsRecursively(TypeMirror tm) { 277 switch (tm.getKind()) { 278 case WILDCARD: 279 case TYPEVAR: 280 case ERROR: 281 return true; 282 case DECLARED: 283 DeclaredType type = (DeclaredType) tm; 284 285 for (TypeMirror t : type.getTypeArguments()) { 286 if (containsErrorsOrTypevarsRecursively(t)) 287 return true; 288 } 289 290 return false; 291 case ARRAY: 292 return containsErrorsOrTypevarsRecursively(((ArrayType) tm).getComponentType()); 293 default: 294 return false; 295 } 296 } 297 298 private static EnumSet <Modifier> getAccessModifiers(TypeElement source, TypeElement target) { 299 TypeElement outterMostSource = SourceUtils.getOutermostEnclosingTypeElement(source); 300 TypeElement outterMostTarget = SourceUtils.getOutermostEnclosingTypeElement(target); 301 302 if (outterMostSource.equals(outterMostTarget)) { 303 return EnumSet.of(Modifier.PRIVATE); 304 } 305 306 Element sourcePackage = outterMostSource.getEnclosingElement(); 307 Element targetPackage = outterMostTarget.getEnclosingElement(); 308 309 if (sourcePackage.equals(targetPackage)) { 310 return EnumSet.noneOf(Modifier.class); 311 } 312 313 return EnumSet.of(Modifier.PUBLIC); 315 } 316 317 private static enum FixTypes { 318 PARAM, LOCAL, FIELD 319 } 320 321 private static List <? extends TypeMirror> resolveType(Set <FixTypes> types, CompilationInfo info, TreePath currentPath, Tree unresolved, int offset) { 322 switch (currentPath.getLeaf().getKind()) { 323 case METHOD: 324 return computeMethod(types, info, currentPath, unresolved, offset); 325 case MEMBER_SELECT: 326 return computeMemberSelect(types, info, currentPath, unresolved, offset); 327 case ASSIGNMENT: 328 return computeAssignment(types, info, currentPath, unresolved, offset); 329 case ENHANCED_FOR_LOOP: 330 return computeEnhancedForLoop(types, info, currentPath, unresolved, offset); 331 case ARRAY_ACCESS: 332 return computeArrayAccess(types, info, currentPath, unresolved, offset); 333 case VARIABLE: 334 return computeVariableDeclaration(types, info, currentPath, unresolved, offset); 335 case ASSERT: 336 return computeAssert(types, info, currentPath, unresolved, offset); 337 case PARENTHESIZED: 338 return computeParenthesis(types, info, currentPath, unresolved, offset); 339 case DO_WHILE_LOOP: 340 return computePrimitiveType(types, info, ((DoWhileLoopTree) currentPath.getLeaf()).getCondition(), unresolved, TypeKind.BOOLEAN); 341 case FOR_LOOP: 342 return computePrimitiveType(types, info, ((ForLoopTree) currentPath.getLeaf()).getCondition(), unresolved, TypeKind.BOOLEAN); 343 case IF: 344 return computePrimitiveType(types, info, ((IfTree) currentPath.getLeaf()).getCondition(), unresolved, TypeKind.BOOLEAN); 345 case WHILE_LOOP: 346 return computePrimitiveType(types, info, ((WhileLoopTree) currentPath.getLeaf()).getCondition(), unresolved, TypeKind.BOOLEAN); 347 case SYNCHRONIZED: 348 return computeReferenceType(types, info, ((SynchronizedTree) currentPath.getLeaf()).getExpression(), unresolved, "java.lang.Object"); 349 case THROW: 350 return computeReferenceType(types, info, ((ThrowTree) currentPath.getLeaf()).getExpression(), unresolved, "java.lang.Exception"); 351 case INSTANCE_OF: 352 return computeReferenceType(types, info, ((InstanceOfTree) currentPath.getLeaf()).getExpression(), unresolved, "java.lang.Object"); 353 case SWITCH: 354 return computePrimitiveType(types, info, ((SwitchTree) currentPath.getLeaf()).getExpression(), unresolved, TypeKind.INT); 356 case RETURN: 357 return computeReturn(types, info, currentPath, unresolved, offset); 358 359 case POSTFIX_INCREMENT: 360 case POSTFIX_DECREMENT: 361 case PREFIX_INCREMENT: 362 case PREFIX_DECREMENT: 363 case UNARY_PLUS: 364 case UNARY_MINUS: 365 case BITWISE_COMPLEMENT: 366 case LOGICAL_COMPLEMENT: 367 return computeUnary(types, info, currentPath, unresolved, offset); 368 369 case MULTIPLY: 370 case DIVIDE: 371 case REMAINDER: 372 case PLUS: 373 case MINUS: 374 case LEFT_SHIFT: 375 case RIGHT_SHIFT: 376 case UNSIGNED_RIGHT_SHIFT: 377 case LESS_THAN: 378 case GREATER_THAN: 379 case LESS_THAN_EQUAL: 380 case GREATER_THAN_EQUAL: 381 case EQUAL_TO: 382 case NOT_EQUAL_TO: 383 case AND: 384 case XOR: 385 case OR: 386 case CONDITIONAL_AND: 387 case CONDITIONAL_OR: 388 return computeBinaryOperator(types, info, currentPath, unresolved, offset); 389 390 case MULTIPLY_ASSIGNMENT: 391 case DIVIDE_ASSIGNMENT: 392 case REMAINDER_ASSIGNMENT: 393 case PLUS_ASSIGNMENT: 394 case MINUS_ASSIGNMENT: 395 case LEFT_SHIFT_ASSIGNMENT: 396 case RIGHT_SHIFT_ASSIGNMENT: 397 case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT: 398 case AND_ASSIGNMENT: 399 case XOR_ASSIGNMENT: 400 case OR_ASSIGNMENT: 401 return null; 403 404 case ARRAY_TYPE: 405 case BLOCK: 406 case BREAK: 407 case CATCH: 408 case CLASS: 409 case COMPILATION_UNIT: 410 case CONTINUE: 411 case EXPRESSION_STATEMENT: 412 case IMPORT: 413 case IDENTIFIER: 414 case TYPE_CAST: 415 case PARAMETERIZED_TYPE: 416 case TRY: 417 case EMPTY_STATEMENT: 418 case PRIMITIVE_TYPE: 419 case LABELED_STATEMENT: 420 case MODIFIERS: 421 case ERRONEOUS: 422 case OTHER: 423 case INT_LITERAL: 424 case LONG_LITERAL: 425 case FLOAT_LITERAL: 426 case DOUBLE_LITERAL: 427 case BOOLEAN_LITERAL: 428 case CHAR_LITERAL: 429 case STRING_LITERAL: 430 case NULL_LITERAL: 431 case TYPE_PARAMETER: 432 return null; 434 435 case CASE: 436 case ANNOTATION: 437 case CONDITIONAL_EXPRESSION: 438 case NEW_ARRAY: 439 case NEW_CLASS: 440 case UNBOUNDED_WILDCARD: 441 case EXTENDS_WILDCARD: 442 case SUPER_WILDCARD: 443 return null; 445 446 default: 447 return null; 449 } 450 } 451 452 private static List <? extends TypeMirror> computeBinaryOperator(Set <FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) { 453 BinaryTree bt = (BinaryTree) parent.getLeaf(); 454 TreePath typeToResolve = null; 455 456 if (bt.getLeftOperand() == error) { 457 typeToResolve = new TreePath(parent, bt.getRightOperand()); 458 } 459 460 if (bt.getRightOperand() == error) { 461 typeToResolve = new TreePath(parent, bt.getLeftOperand()); 462 } 463 464 types.add(FixTypes.PARAM); 465 types.add(FixTypes.LOCAL); 466 types.add(FixTypes.FIELD); 467 468 return typeToResolve != null ? Collections.singletonList(info.getTrees().getTypeMirror(typeToResolve)) : null; 469 } 470 471 private static List <? extends TypeMirror> computeMethod(Set <FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) { 472 MethodTree mt = (MethodTree) parent.getLeaf(); 476 477 if (mt.getBody() == null) { 478 return null; 479 } 480 481 try { 482 int bodyStart = Utilities.findBodyStart(parent.getLeaf(), info.getCompilationUnit(), info.getTrees().getSourcePositions(), info.getDocument()); 483 int bodyEnd = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), parent.getLeaf()); 484 485 types.add(FixTypes.PARAM); 486 types.add(FixTypes.LOCAL); 487 types.add(FixTypes.FIELD); 488 489 if (bodyStart <= offset && offset <= bodyEnd) 490 return Collections.singletonList(info.getElements().getTypeElement("java.lang.Object").asType()); 491 } catch (IOException ex) { 492 Logger.getLogger("global").log(Level.INFO, ex.getMessage(), ex); 493 } 494 495 return null; 496 } 497 498 private static List <? extends TypeMirror> computeMemberSelect(Set <FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) { 499 MemberSelectTree ms = (MemberSelectTree) parent.getLeaf(); 501 if (!"class".equals(ms.getIdentifier().toString())) { types.add(FixTypes.FIELD); 503 return Collections.singletonList(info.getElements().getTypeElement("java.lang.Object").asType()); 504 } 505 506 return null; 507 } 508 509 private static List <? extends TypeMirror> computeAssignment(Set <FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) { 510 AssignmentTree at = (AssignmentTree) parent.getLeaf(); 511 TypeMirror type = null; 512 513 if (at.getVariable() == error) { 514 type = info.getTrees().getTypeMirror(new TreePath(parent, at.getExpression())); 515 516 if (type.getKind() == TypeKind.EXECUTABLE) { 517 type = ((ExecutableType) type).getReturnType(); 522 } 523 } 524 525 if (at.getExpression() == error) { 526 type = info.getTrees().getTypeMirror(new TreePath(parent, at.getVariable())); 527 } 528 529 if (type == null) { 531 if (JavaHintsProvider.ERR.isLoggable(ErrorManager.INFORMATIONAL)) { 532 JavaHintsProvider.ERR.log(ErrorManager.INFORMATIONAL, "offset=" + offset); 533 JavaHintsProvider.ERR.log(ErrorManager.INFORMATIONAL, "errorTree=" + error); 534 JavaHintsProvider.ERR.log(ErrorManager.INFORMATIONAL, "type=null"); 535 } 536 537 return null; 538 } 539 540 types.add(FixTypes.PARAM); 541 types.add(FixTypes.LOCAL); 542 types.add(FixTypes.FIELD); 543 544 return Collections.singletonList(type); 545 } 546 547 private static List <? extends TypeMirror> computeEnhancedForLoop(Set <FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) { 548 EnhancedForLoopTree efl = (EnhancedForLoopTree) parent.getLeaf(); 549 550 if (efl.getExpression() != error) { 551 return null; 552 } 553 554 types.add(FixTypes.PARAM); 555 types.add(FixTypes.LOCAL); 556 types.add(FixTypes.FIELD); 557 558 TypeElement iterable = info.getElements().getTypeElement("java.lang.Iterable"); 559 TypeMirror argument = info.getTrees().getTypeMirror(new TreePath(new TreePath(parent, efl.getVariable()), efl.getVariable().getType())); 560 561 return Collections.singletonList(info.getTypes().getDeclaredType(iterable, argument)); 562 } 563 564 private static List <? extends TypeMirror> computeArrayAccess(Set <FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) { 565 ArrayAccessTree aat = (ArrayAccessTree) parent.getLeaf(); 566 567 if (aat.getExpression() == error) { 568 TreePath parentParent = parent.getParentPath(); 569 List <? extends TypeMirror> upperTypes = resolveType(types, info, parentParent, aat, offset); 570 571 if (upperTypes == null) { 572 return null; 573 } 574 575 List <TypeMirror> arrayTypes = new ArrayList <TypeMirror>(); 576 577 for (TypeMirror tm : upperTypes) { 578 arrayTypes.add(info.getTypes().getArrayType(tm)); 579 } 580 581 return arrayTypes; 582 } 583 584 if (aat.getIndex() == error) { 585 types.add(FixTypes.PARAM); 586 types.add(FixTypes.LOCAL); 587 types.add(FixTypes.FIELD); 588 589 return Collections.singletonList(info.getTypes().getPrimitiveType(TypeKind.INT)); 590 } 591 592 return null; 593 } 594 595 private static List <? extends TypeMirror> computeVariableDeclaration(Set <FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) { 596 VariableTree vt = (VariableTree) parent.getLeaf(); 597 598 if (vt.getInitializer() != error) { 599 return null; 600 } 601 602 types.add(FixTypes.PARAM); 603 types.add(FixTypes.LOCAL); 604 types.add(FixTypes.FIELD); 605 606 return Collections.singletonList(info.getTrees().getTypeMirror(new TreePath(parent, vt.getType()))); 607 } 608 609 private static List <? extends TypeMirror> computeAssert(Set <FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) { 610 AssertTree at = (AssertTree) parent.getLeaf(); 611 612 types.add(FixTypes.PARAM); 613 types.add(FixTypes.LOCAL); 614 types.add(FixTypes.FIELD); 615 616 if (at.getCondition() == error) { 617 return Collections.singletonList(info.getTypes().getPrimitiveType(TypeKind.BOOLEAN)); 618 } 619 620 if (at.getDetail() == error) { 621 return Collections.singletonList(info.getElements().getTypeElement("java.lang.Object").asType()); 622 } 623 624 625 return null; 626 } 627 628 private static List <? extends TypeMirror> computeParenthesis(Set <FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) { 629 ParenthesizedTree pt = (ParenthesizedTree) parent.getLeaf(); 630 631 if (pt.getExpression() != error) { 632 return null; 633 } 634 635 TreePath parentParent = parent.getParentPath(); 636 List <? extends TypeMirror> upperTypes = resolveType(types, info, parentParent, pt, offset); 637 638 if (upperTypes == null) { 639 return null; 640 } 641 642 return upperTypes; 643 } 644 645 private static List <? extends TypeMirror> computePrimitiveType(Set <FixTypes> types, CompilationInfo info, Tree expression, Tree error, TypeKind kind) { 646 if (expression == error) { 647 types.add(FixTypes.PARAM); 648 types.add(FixTypes.LOCAL); 649 types.add(FixTypes.FIELD); 650 651 return Collections.singletonList(info.getTypes().getPrimitiveType(kind)); 652 } 653 654 return null; 655 } 656 657 private static List <? extends TypeMirror> computeReferenceType(Set <FixTypes> types, CompilationInfo info, Tree expression, Tree error, String type) { 658 if (expression == error) { 659 types.add(FixTypes.PARAM); 660 types.add(FixTypes.LOCAL); 661 types.add(FixTypes.FIELD); 662 663 return Collections.singletonList(info.getElements().getTypeElement(type).asType()); 664 } 665 666 return null; 667 } 668 669 private static List <? extends TypeMirror> computeUnary(Set <FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) { 670 UnaryTree tree = (UnaryTree) parent.getLeaf(); 671 672 if (tree.getExpression() == error) { 673 List <? extends TypeMirror> parentTypes = resolveType(types, info, parent.getParentPath(), tree, offset); 674 675 if (parentTypes == null) { 676 types.add(FixTypes.PARAM); 677 types.add(FixTypes.LOCAL); 678 types.add(FixTypes.FIELD); 679 680 return Collections.singletonList(info.getTypes().getPrimitiveType(TypeKind.INT)); 681 } 682 683 return parentTypes; 684 } 685 686 return null; 687 } 688 689 private static List <? extends TypeMirror> computeReturn(Set <FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) { 690 ReturnTree rt = (ReturnTree) parent.getLeaf(); 691 692 if (rt.getExpression() == error) { 693 TreePath method = findMethod(parent); 694 695 if (method == null) { 696 return null; 697 } 698 699 Element el = info.getTrees().getElement(method); 700 701 if (el == null || el.getKind() != ElementKind.METHOD) { 702 return null; 703 } 704 705 types.add(FixTypes.PARAM); 706 types.add(FixTypes.LOCAL); 707 types.add(FixTypes.FIELD); 708 709 return Collections.singletonList(((ExecutableElement) el).getReturnType()); 710 } 711 712 return null; 713 } 714 715 private static final Set <Kind> STOP_LOOKING_FOR_METHOD = EnumSet.of(Kind.METHOD, Kind.CLASS, Kind.COMPILATION_UNIT); 716 717 private static TreePath findMethod(TreePath tp) { 718 while (!STOP_LOOKING_FOR_METHOD.contains(tp.getLeaf().getKind())) { 719 tp = tp.getParentPath(); 720 } 721 722 if (tp.getLeaf().getKind() == Kind.METHOD) { 723 return tp; 724 } 725 726 return null; 727 } 728 729 static final class CreateFieldFix implements Fix { 730 731 private FileObject targetFile; 732 private ElementHandle<TypeElement> target; 733 private TypeMirrorHandle proposedType; 734 private ClasspathInfo cpInfo; 735 private Set <Modifier> modifiers; 736 737 private String name; 738 private String inFQN; 739 740 public CreateFieldFix(CompilationInfo info, String name, Set <Modifier> modifiers, TypeElement target, TypeMirror proposedType) { 741 this.name = name; 742 this.inFQN = target.getQualifiedName().toString(); 743 this.cpInfo = info.getClasspathInfo(); 744 this.modifiers = modifiers; 745 this.targetFile = SourceUtils.getFile(target, cpInfo); 746 this.target = ElementHandle.create(target); 747 if (proposedType.getKind() == TypeKind.NULL) { 748 proposedType = info.getElements().getTypeElement("java.lang.Object").asType(); 749 } 750 this.proposedType = TypeMirrorHandle.create(proposedType); 751 } 752 753 public String getText() { 754 return "Create field " + name + " in " + inFQN; 755 } 756 757 public ChangeInfo implement() { 758 try { 759 JavaSource js = JavaSource.create(cpInfo, targetFile); 761 762 js.runModificationTask(new CancellableTask<WorkingCopy>() { 763 public void cancel() { 764 } 765 public void run(final WorkingCopy working) throws IOException { 766 working.toPhase(Phase.RESOLVED); 767 TypeElement targetType = target.resolve(working); 768 769 if (targetType == null) { 770 JavaHintsProvider.LOG.log(Level.INFO, "Cannot resolve target."); 771 return; 772 } 773 774 ClassTree targetTree = working.getTrees().getTree(targetType); 775 776 if (targetTree == null) { 777 JavaHintsProvider.LOG.log(Level.INFO, "Cannot resolve target tree: " + targetType.getQualifiedName() + "."); 778 return; 779 } 780 781 TypeMirror proposedType = CreateFieldFix.this.proposedType.resolve(working); 782 783 if (proposedType == null) { 784 JavaHintsProvider.LOG.log(Level.INFO, "Cannot resolve proposed type."); 785 return; 786 } 787 788 TreeMaker make = working.getTreeMaker(); 789 TypeMirror tm = proposedType; 790 VariableTree var = null; 791 792 if (tm.getKind() == TypeKind.DECLARED || tm.getKind() == TypeKind.ARRAY) { 793 var = make.Variable(make.Modifiers(modifiers), name, make.Type(tm), null); 794 } 795 796 if (tm.getKind().isPrimitive()) { 797 var = make.Variable(make.Modifiers(modifiers), name, make.Type(tm), null); 798 } 799 800 assert var != null : tm.getKind(); 801 ClassTree decl = make.addClassMember(targetTree, var); 802 working.rewrite(targetTree, decl); 803 } 804 }).commit(); 805 } catch (IOException e) { 806 throw (IllegalStateException ) new IllegalStateException ().initCause(e); 807 } 808 809 return null; 810 } 811 812 String toDebugString(CompilationInfo info) { 813 return "CreateFieldFix:" + name + ":" + target.getQualifiedName() + ":" + proposedType.resolve(info).toString() + ":" + modifiers; 814 } 815 } 816 817 } 818 | Popular Tags |