1 11 package org.eclipse.jdt.internal.corext.template.java; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.HashMap ; 16 import java.util.List ; 17 import java.util.ListIterator ; 18 import java.util.Map ; 19 20 import org.eclipse.core.runtime.Assert; 21 import org.eclipse.core.runtime.CoreException; 22 import org.eclipse.core.runtime.IStatus; 23 import org.eclipse.core.runtime.Status; 24 25 26 import org.eclipse.jdt.core.CompletionProposal; 27 import org.eclipse.jdt.core.CompletionRequestor; 28 import org.eclipse.jdt.core.ICompilationUnit; 29 import org.eclipse.jdt.core.IJavaProject; 30 import org.eclipse.jdt.core.IType; 31 import org.eclipse.jdt.core.ITypeHierarchy; 32 import org.eclipse.jdt.core.ITypeParameter; 33 import org.eclipse.jdt.core.JavaModelException; 34 import org.eclipse.jdt.core.Signature; 35 import org.eclipse.jdt.core.compiler.IProblem; 36 37 import org.eclipse.jdt.internal.ui.JavaPlugin; 38 39 43 final class CompilationUnitCompletion extends CompletionRequestor { 44 45 50 public final class Variable { 51 private static final int UNKNOWN= 0, NONE= 0; 52 private static final int ARRAY= 1; 53 private static final int COLLECTION= 2; 54 private static final int ITERABLE= 4; 55 56 59 private final String name; 60 61 64 private final String signature; 65 66 67 private int fType= UNKNOWN; 68 private int fChecked= NONE; 69 private String [] fMemberTypes; 70 71 private Variable(String name, String signature) { 72 this.name= name; 73 this.signature= signature; 74 } 75 76 81 public String getName() { 82 return name; 83 } 84 85 92 public boolean isArray() { 93 if (fType == UNKNOWN && (fChecked & ARRAY) == 0 && Signature.getTypeSignatureKind(signature) == Signature.ARRAY_TYPE_SIGNATURE) 94 fType= ARRAY; 95 fChecked |= ARRAY; 96 return fType == ARRAY; 97 } 98 99 107 public boolean isCollection() { 108 if ((fType == UNKNOWN || fType == ITERABLE) && (fChecked & COLLECTION) == 0 && isSubtypeOf("java.util.Collection")) fType= COLLECTION; 111 fChecked |= COLLECTION; 112 return fType == COLLECTION; 113 } 114 115 123 public boolean isIterable() { 124 if (fType == UNKNOWN && (fChecked & ITERABLE) == 0 && isSubtypeOf("java.lang.Iterable")) fType= ITERABLE; 126 fChecked |= ITERABLE; 127 return fType == ITERABLE || fType == COLLECTION; } 129 130 138 private boolean isSubtypeOf(String supertype) { 139 String implementorName= SignatureUtil.stripSignatureToFQN(signature); 140 if (implementorName.length() == 0) 141 return false; 142 143 boolean qualified= supertype.indexOf('.') != -1; 144 145 if (implementorName.equals(supertype) || !qualified && Signature.getSimpleName(implementorName).equals(supertype)) 147 return true; 148 149 if (fUnit == null) 150 return false; 151 152 IJavaProject project= fUnit.getJavaProject(); 153 154 try { 155 IType sub= project.findType(implementorName); 156 if (sub == null) 157 return false; 158 159 if (qualified) { 160 IType sup= project.findType(supertype); 161 if (sup == null) 162 return false; 163 ITypeHierarchy hierarchy= sub.newSupertypeHierarchy(null); 164 return hierarchy.contains(sup); 165 } else { 166 ITypeHierarchy hierarchy= sub.newSupertypeHierarchy(null); 167 IType[] allTypes= hierarchy.getAllTypes(); 168 for (int i= 0; i < allTypes.length; i++) { 169 IType type= allTypes[i]; 170 if (type.getElementName().equals(supertype)) 171 return true; 172 } 173 } 174 175 } catch (JavaModelException e) { 176 } 178 179 return false; 180 } 181 182 private IType[] getSupertypes(String supertype) { 183 IType[] empty= new IType[0]; 184 String implementorName= SignatureUtil.stripSignatureToFQN(signature); 185 if (implementorName.length() == 0) 186 return empty; 187 188 boolean qualified= supertype.indexOf('.') != -1; 189 190 if (fUnit == null) 191 return empty; 192 193 IJavaProject project= fUnit.getJavaProject(); 194 195 try { 196 IType sub= project.findType(implementorName); 197 if (sub == null) 198 return empty; 199 200 if (qualified) { 201 IType sup= project.findType(supertype); 202 if (sup == null) 203 return empty; 204 return new IType[] {sup}; 205 } else { 206 ITypeHierarchy hierarchy= sub.newSupertypeHierarchy(null); 207 IType[] allTypes= hierarchy.getAllTypes(); 208 List matches= new ArrayList (); 209 for (int i= 0; i < allTypes.length; i++) { 210 IType type= allTypes[i]; 211 if (type.getElementName().equals(supertype)) 212 matches.add(type); 213 } 214 return (IType[]) matches.toArray(new IType[matches.size()]); 215 } 216 217 } catch (JavaModelException e) { 218 } 220 221 return empty; 222 } 223 224 229 public String getMemberTypeSignature() { 230 return getMemberTypeSignatures()[0]; 231 } 232 233 238 public String [] getMemberTypeSignatures() { 239 if (isArray()) { 240 return new String [] {Signature.createArraySignature(Signature.getElementType(signature), Signature.getArrayCount(signature) - 1)}; 241 } else if (fUnit != null && (isIterable() || isCollection())) { 242 if (fMemberTypes == null) { 243 try { 244 try { 245 TypeParameterResolver util= new TypeParameterResolver(this); 246 fMemberTypes= util.computeBinding("java.lang.Iterable", 0); } catch (JavaModelException e) { 248 try { 249 TypeParameterResolver util= new TypeParameterResolver(this); 250 fMemberTypes= util.computeBinding("java.util.Collection", 0); } catch (JavaModelException x) { 252 fMemberTypes= new String [0]; 253 } 254 } 255 } catch (IndexOutOfBoundsException e) { 256 fMemberTypes= new String [0]; 257 } 258 } 259 if (fMemberTypes.length > 0) 260 return fMemberTypes; 261 } 262 return new String [] {Signature.createTypeSignature("java.lang.Object", true)}; } 264 265 271 public String [] getMemberTypeNames() { 272 String [] signatures= getMemberTypeSignatures(); 273 String [] names= new String [signatures.length]; 274 275 for (int i= 0; i < signatures.length; i++) { 276 String sig= signatures[i]; 277 String local= (String ) fLocalTypes.get(Signature.getElementType(sig)); 278 int dim= Signature.getArrayCount(sig); 279 if (local != null && dim > 0) { 280 StringBuffer array= new StringBuffer (local); 281 for (int j= 0; j < dim; j++) 282 array.append("[]"); local= array.toString(); 284 } 285 if (local != null) 286 names[i]= local; 287 else 288 names[i]= Signature.getSimpleName(Signature.getSignatureSimpleName(sig)); 289 } 290 return names; 291 } 292 293 302 public String [] getTypeArgumentBoundSignatures(String type, int index) { 303 List all= new ArrayList (); 304 IType[] supertypes= getSupertypes(type); 305 if (fUnit != null) { 306 for (int i= 0; i < supertypes.length; i++) { 307 try { 308 TypeParameterResolver util= new TypeParameterResolver(this); 309 String [] result= util.computeBinding(supertypes[i].getFullyQualifiedName(), index); 310 all.addAll(Arrays.asList(result)); 311 } catch (JavaModelException e) { 312 } catch (IndexOutOfBoundsException e) { 313 } 314 } 315 } 316 if (all.isEmpty()) 317 return new String [] {Signature.createTypeSignature("java.lang.Object", true)}; return (String []) all.toArray(new String [all.size()]); 319 } 320 321 324 public String toString() { 325 String type; 326 switch (fType) { 327 case ITERABLE: 328 type= "ITERABLE"; break; 330 case COLLECTION: 331 type= "COLLECTION"; break; 333 case ARRAY: 334 type= "ARRAY"; break; 336 default: 337 type= "UNKNOWN"; break; 339 } 340 return "LocalVariable [name=\"" + name + "\" signature=\"" + signature + "\" type=\"" + type + "\" member=\"" + getMemberTypeSignature() + "\"]"; } 342 } 343 344 349 private final class TypeParameterResolver { 350 private static final String OBJECT_SIGNATURE= "Ljava.lang.Object;"; 352 private final ITypeHierarchy fHierarchy; 353 private final Variable fVariable; 354 private final IType fType; 355 private final List fBounds= new ArrayList (); 356 357 369 public TypeParameterResolver(Variable variable) throws JavaModelException { 370 String typeName= SignatureUtil.stripSignatureToFQN(variable.signature); 371 IJavaProject project= fUnit.getJavaProject(); 372 fType= project.findType(typeName); 373 fHierarchy= fType.newSupertypeHierarchy(null); 374 fVariable= variable; 375 } 376 377 394 public String [] computeBinding(String superType, int index) throws JavaModelException, IndexOutOfBoundsException { 395 IJavaProject project= fUnit.getJavaProject(); 396 IType type= project.findType(superType); 397 if (type == null) 398 throw new JavaModelException(new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.OK, "No such type", null))); return computeBinding(type, index); 400 } 401 402 419 public String [] computeBinding(IType superType, int index) throws JavaModelException, IndexOutOfBoundsException { 420 initBounds(); 421 computeTypeParameterBinding(superType, index); 422 return (String []) fBounds.toArray(new String [fBounds.size()]); 423 } 424 425 445 private void computeTypeParameterBinding(final IType superType, final int index) throws JavaModelException, IndexOutOfBoundsException { 446 int nParameters= superType.getTypeParameters().length; 447 if (nParameters <= index) 448 throw new IndexOutOfBoundsException (); 449 450 IType[] subTypes= fHierarchy.getSubtypes(superType); 451 452 if (subTypes.length == 0) { 453 Assert.isTrue(superType.equals(fType)); 455 456 String match= findMatchingTypeArgument(fVariable.signature, index, fUnit.findPrimaryType()); 457 String bound= SignatureUtil.getUpperBound(match); 458 459 addBound(bound); 463 return; 464 } 465 466 IType subType= subTypes[0]; 468 String signature= findMatchingSuperTypeSignature(subType, superType); 469 String match= findMatchingTypeArgument(signature, index, subType); 470 471 if (isConcreteType(match, subType)) { 472 addBound(match); 473 return; 474 } 475 476 ITypeParameter[] typeParameters= subType.getTypeParameters(); 477 478 for (int k= 0; k < typeParameters.length; k++) { 479 ITypeParameter formalParameter= typeParameters[k]; 480 if (formalParameter.getElementName().equals(SignatureUtil.stripSignatureToFQN(match))) { 481 String [] bounds= formalParameter.getBounds(); 482 for (int i= 0; i < bounds.length; i++) { 483 String boundSignature= Signature.createTypeSignature(bounds[i], true); 484 addBound(SignatureUtil.qualifySignature(boundSignature, subType)); 485 } 486 computeTypeParameterBinding(subType, k); 487 return; 488 } 489 } 490 491 addBound(match); 496 return; 497 } 498 499 521 private String findMatchingTypeArgument(String signature, int index, IType context) throws IndexOutOfBoundsException { 522 String [] typeArguments= Signature.getTypeArguments(signature); 523 if (typeArguments.length > 0 && typeArguments.length <= index) 524 throw new IndexOutOfBoundsException (); 525 if (typeArguments.length == 0) { 526 return OBJECT_SIGNATURE; 528 } else { 529 String bound= SignatureUtil.getUpperBound(typeArguments[index]); 530 return SignatureUtil.qualifySignature(bound, context); 531 } 532 } 533 534 548 private String findMatchingSuperTypeSignature(IType subType, IType superType) throws JavaModelException { 549 String [] signatures= getSuperTypeSignatures(subType, superType); 550 for (int i= 0; i < signatures.length; i++) { 551 String signature= signatures[i]; 552 String qualified= SignatureUtil.qualifySignature(signature, subType); 553 String subFQN= SignatureUtil.stripSignatureToFQN(qualified); 554 555 String superFQN= superType.getFullyQualifiedName(); 556 if (subFQN.equals(superFQN)) { 557 return signature; 558 } 559 560 if (fLocalTypes.containsValue(subFQN)) { 562 return signature; 563 } 564 } 565 566 throw new JavaModelException(new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.OK, "Illegal hierarchy", null))); } 568 569 579 private String [] getSuperTypeSignatures(IType subType, IType superType) throws JavaModelException { 580 if (superType.isInterface()) 581 return subType.getSuperInterfaceTypeSignatures(); 582 else 583 return new String [] {subType.getSuperclassTypeSignature()}; 584 } 585 586 590 private void initBounds() { 591 fBounds.clear(); 592 fBounds.add(OBJECT_SIGNATURE); 593 } 594 595 602 private void addBound(String boundSignature) { 603 if (SignatureUtil.isJavaLangObject(boundSignature)) 604 return; 605 606 boolean found= false; 607 for (ListIterator it= fBounds.listIterator(); it.hasNext();) { 608 String old= (String ) it.next(); 609 if (isTrueSubtypeOf(boundSignature, old)) { 610 if (!found) { 611 it.set(boundSignature); 612 found= true; 613 } else { 614 it.remove(); 615 } 616 } 617 } 618 if (!found) 619 fBounds.add(boundSignature); 620 } 621 622 631 private boolean isTrueSubtypeOf(String subTypeSignature, String superTypeSignature) { 632 if (subTypeSignature.equals(superTypeSignature)) 634 return true; 635 636 if (SignatureUtil.isJavaLangObject(subTypeSignature)) 637 return false; 639 if (Signature.getTypeSignatureKind(subTypeSignature) != Signature.BASE_TYPE_SIGNATURE && SignatureUtil.isJavaLangObject(superTypeSignature)) 640 return true; 641 642 IJavaProject project= fUnit.getJavaProject(); 643 644 try { 645 646 if ((Signature.getTypeSignatureKind(subTypeSignature) & (Signature.TYPE_VARIABLE_SIGNATURE | Signature.CLASS_TYPE_SIGNATURE)) == 0) 647 return false; 648 IType subType= project.findType(SignatureUtil.stripSignatureToFQN(subTypeSignature)); 649 if (subType == null) 650 return false; 651 652 if ((Signature.getTypeSignatureKind(superTypeSignature) & (Signature.TYPE_VARIABLE_SIGNATURE | Signature.CLASS_TYPE_SIGNATURE)) == 0) 653 return false; 654 IType superType= project.findType(SignatureUtil.stripSignatureToFQN(superTypeSignature)); 655 if (superType == null) 656 return false; 657 658 ITypeHierarchy hierarchy= subType.newSupertypeHierarchy(null); 659 IType[] types= hierarchy.getAllSupertypes(subType); 660 661 for (int i= 0; i < types.length; i++) 662 if (types[i].equals(superType)) 663 return true; 664 } catch (JavaModelException e) { 665 } 667 668 return false; 669 } 670 671 679 private boolean isConcreteType(String signature, IType context) throws JavaModelException { 680 if (Signature.TYPE_VARIABLE_SIGNATURE == Signature.getTypeSignatureKind(signature)) 682 return false; 683 684 if (context.isBinary()) { 686 return fUnit.getJavaProject().findType(SignatureUtil.stripSignatureToFQN(signature)) != null; 687 } else { 688 return context.resolveType(SignatureUtil.stripSignatureToFQN(signature)) != null; 689 } 690 } 691 } 692 693 private ICompilationUnit fUnit; 694 695 private List fLocalVariables= new ArrayList (); 696 private List fFields= new ArrayList (); 697 private Map fLocalTypes= new HashMap (); 698 699 private boolean fError; 700 701 706 CompilationUnitCompletion(ICompilationUnit unit) { 707 reset(unit); 708 setIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION, true); 709 setIgnored(CompletionProposal.KEYWORD, true); 710 setIgnored(CompletionProposal.LABEL_REF, true); 711 setIgnored(CompletionProposal.METHOD_DECLARATION, true); 712 setIgnored(CompletionProposal.METHOD_NAME_REFERENCE, true); 713 setIgnored(CompletionProposal.METHOD_REF, true); 714 setIgnored(CompletionProposal.PACKAGE_REF, true); 715 setIgnored(CompletionProposal.POTENTIAL_METHOD_DECLARATION, true); 716 setIgnored(CompletionProposal.VARIABLE_DECLARATION, true); 717 setIgnored(CompletionProposal.TYPE_REF, true); 718 } 719 720 725 private void reset(ICompilationUnit unit) { 726 fUnit= unit; 727 fLocalVariables.clear(); 728 fFields.clear(); 729 fLocalTypes.clear(); 730 731 if (fUnit != null) { 732 try { 733 IType[] cuTypes= fUnit.getAllTypes(); 734 for (int i= 0; i < cuTypes.length; i++) { 735 String fqn= cuTypes[i].getFullyQualifiedName(); 736 String sig= Signature.createTypeSignature(fqn, true); 737 fLocalTypes.put(sig, cuTypes[i].getElementName()); 738 } 739 } catch (JavaModelException e) { 740 } 742 } 743 fError= false; 744 } 745 746 749 public void accept(CompletionProposal proposal) { 750 751 String name= String.valueOf(proposal.getCompletion()); 752 String signature= String.valueOf(proposal.getSignature()); 753 754 switch (proposal.getKind()) { 755 756 case CompletionProposal.LOCAL_VARIABLE_REF: 757 fLocalVariables.add(new Variable(name, signature)); 759 break; 760 case CompletionProposal.FIELD_REF: 761 fFields.add(new Variable(name, signature)); 763 break; 764 765 default: 766 break; 767 } 768 } 769 770 773 public void completionFailure(IProblem problem) { 774 fError= true; 775 } 776 777 783 public boolean hasErrors() { 784 return fError; 785 } 786 787 792 public String [] getLocalVariableNames() { 793 String [] names= new String [fLocalVariables.size()]; 794 int i= 0; 795 for (ListIterator iterator= fLocalVariables.listIterator(fLocalVariables.size()); iterator.hasPrevious();) { 796 Variable localVariable= (Variable) iterator.previous(); 797 names[i++]= localVariable.getName(); 798 } 799 return names; 800 } 801 802 808 public String [] getFieldNames() { 809 String [] names= new String [fFields.size()]; 810 int i= 0; 811 for (ListIterator iterator= fFields.listIterator(fFields.size()); iterator.hasPrevious();) { 812 Variable field= (Variable)iterator.previous(); 813 names[i++]= field.getName(); 814 } 815 return names; 816 } 817 818 823 public Variable[] findLocalArrays() { 824 List arrays= new ArrayList (); 825 826 for (ListIterator iterator= fLocalVariables.listIterator(fLocalVariables.size()); iterator.hasPrevious();) { 827 Variable localVariable= (Variable) iterator.previous(); 828 829 if (localVariable.isArray()) 830 arrays.add(localVariable); 831 } 832 833 return (Variable[]) arrays.toArray(new Variable[arrays.size()]); 834 } 835 836 843 public Variable[] findLocalVariables(String clazz) { 844 List matches= new ArrayList (); 845 846 for (ListIterator iterator= fLocalVariables.listIterator(fLocalVariables.size()); iterator.hasPrevious();) { 847 Variable localVariable= (Variable) iterator.previous(); 848 849 if (localVariable.isSubtypeOf(clazz)) 850 matches.add(localVariable); 851 } 852 853 return (Variable[]) matches.toArray(new Variable[matches.size()]); 854 } 855 856 863 public Variable[] findFieldVariables(String clazz) { 864 List matches= new ArrayList (); 865 866 for (ListIterator iterator= fFields.listIterator(fFields.size()); iterator.hasPrevious();) { 867 Variable localVariable= (Variable)iterator.previous(); 868 869 if (localVariable.isSubtypeOf(clazz)) 870 matches.add(localVariable); 871 } 872 873 return (Variable[]) matches.toArray(new Variable[matches.size()]); 874 } 875 876 884 public Variable[] findLocalIterables() { 885 List iterables= new ArrayList (); 886 887 for (ListIterator iterator= fLocalVariables.listIterator(fLocalVariables.size()); iterator.hasPrevious();) { 888 Variable localVariable= (Variable) iterator.previous(); 889 890 if (localVariable.isArray() || localVariable.isIterable()) 891 iterables.add(localVariable); 892 } 893 894 return (Variable[]) iterables.toArray(new Variable[iterables.size()]); 895 } 896 897 } 898 899 | Popular Tags |