1 11 package org.eclipse.jdt.internal.core; 12 13 import java.io.File ; 14 import java.io.FilenameFilter ; 15 import java.io.IOException ; 16 import java.util.ArrayList ; 17 import java.util.Collections ; 18 import java.util.Comparator ; 19 import java.util.Enumeration ; 20 import java.util.HashMap ; 21 import java.util.HashSet ; 22 import java.util.Iterator ; 23 import java.util.Map ; 24 import java.util.Set ; 25 import java.util.zip.ZipEntry ; 26 import java.util.zip.ZipFile ; 27 28 import org.eclipse.core.resources.IContainer; 29 import org.eclipse.core.resources.IFile; 30 import org.eclipse.core.resources.IFolder; 31 import org.eclipse.core.resources.IResource; 32 import org.eclipse.core.resources.ResourcesPlugin; 33 import org.eclipse.core.runtime.CoreException; 34 import org.eclipse.core.runtime.IPath; 35 import org.eclipse.core.runtime.IStatus; 36 import org.eclipse.core.runtime.Path; 37 import org.eclipse.jdt.core.Flags; 38 import org.eclipse.jdt.core.IClassFile; 39 import org.eclipse.jdt.core.IField; 40 import org.eclipse.jdt.core.IJavaElement; 41 import org.eclipse.jdt.core.IJavaProject; 42 import org.eclipse.jdt.core.IMember; 43 import org.eclipse.jdt.core.IMethod; 44 import org.eclipse.jdt.core.IPackageFragmentRoot; 45 import org.eclipse.jdt.core.ISourceRange; 46 import org.eclipse.jdt.core.IType; 47 import org.eclipse.jdt.core.ITypeParameter; 48 import org.eclipse.jdt.core.JavaConventions; 49 import org.eclipse.jdt.core.JavaCore; 50 import org.eclipse.jdt.core.JavaModelException; 51 import org.eclipse.jdt.core.Signature; 52 import org.eclipse.jdt.core.compiler.CategorizedProblem; 53 import org.eclipse.jdt.core.compiler.CharOperation; 54 import org.eclipse.jdt.internal.compiler.IProblemFactory; 55 import org.eclipse.jdt.internal.compiler.ISourceElementRequestor; 56 import org.eclipse.jdt.internal.compiler.SourceElementParser; 57 import org.eclipse.jdt.internal.compiler.env.IBinaryType; 58 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; 59 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; 60 import org.eclipse.jdt.internal.compiler.util.SuffixConstants; 61 import org.eclipse.jdt.internal.compiler.util.Util; 62 import org.eclipse.jdt.internal.core.util.ReferenceInfoAdapter; 63 64 73 public class SourceMapper 74 extends ReferenceInfoAdapter 75 implements ISourceElementRequestor, SuffixConstants { 76 77 public static boolean VERBOSE = false; 78 81 private static final FilenameFilter FILENAME_FILTER = new FilenameFilter () { 82 public boolean accept(File dir, String name) { 83 return org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(name); 84 } 85 }; 86 91 protected ArrayList rootPaths; 92 93 96 protected BinaryType binaryType; 97 98 101 protected IPath sourcePath; 102 107 protected String rootPath = ""; 109 113 protected HashMap parameterNames; 114 115 121 protected HashMap sourceRanges; 122 123 126 protected HashMap categories; 127 128 129 132 public static final SourceRange UNKNOWN_RANGE = new SourceRange(-1, 0); 133 134 138 protected int[] memberDeclarationStart; 139 142 protected SourceRange[] memberNameRange; 143 146 protected String [] memberName; 147 148 151 protected char[][][] methodParameterNames; 152 153 156 protected char[][][] methodParameterTypes; 157 158 159 162 protected IJavaElement searchedElement; 163 164 167 private HashMap importsTable; 168 private HashMap importsCounterTable; 169 170 173 IType[] types; 174 int[] typeDeclarationStarts; 175 SourceRange[] typeNameRanges; 176 int[] typeModifiers; 177 int typeDepth; 178 179 182 int anonymousCounter; 183 int anonymousClassName; 184 185 188 String encoding; 189 Map options; 190 191 194 private boolean areRootPathsComputed; 195 196 public SourceMapper() { 197 this.areRootPathsComputed = false; 198 } 199 200 204 public SourceMapper(IPath sourcePath, String rootPath, Map options) { 205 this.areRootPathsComputed = false; 206 this.options = options; 207 try { 208 this.encoding = ResourcesPlugin.getWorkspace().getRoot().getDefaultCharset(); 209 } catch (CoreException e) { 210 } 212 if (rootPath != null) { 213 this.rootPaths = new ArrayList (); 214 this.rootPaths.add(rootPath); 215 } 216 this.sourcePath = sourcePath; 217 this.sourceRanges = new HashMap (); 218 this.parameterNames = new HashMap (); 219 this.importsTable = new HashMap (); 220 this.importsCounterTable = new HashMap (); 221 } 222 223 226 public void acceptImport( 227 int declarationStart, 228 int declarationEnd, 229 char[][] tokens, 230 boolean onDemand, 231 int modifiers) { 232 char[][] imports = (char[][]) this.importsTable.get(this.binaryType); 233 int importsCounter; 234 if (imports == null) { 235 imports = new char[5][]; 236 importsCounter = 0; 237 } else { 238 importsCounter = ((Integer ) this.importsCounterTable.get(this.binaryType)).intValue(); 239 } 240 if (imports.length == importsCounter) { 241 System.arraycopy( 242 imports, 243 0, 244 (imports = new char[importsCounter * 2][]), 245 0, 246 importsCounter); 247 } 248 char[] name = CharOperation.concatWith(tokens, '.'); 249 if (onDemand) { 250 int nameLength = name.length; 251 System.arraycopy(name, 0, (name = new char[nameLength + 2]), 0, nameLength); 252 name[nameLength] = '.'; 253 name[nameLength + 1] = '*'; 254 } 255 imports[importsCounter++] = name; 256 this.importsTable.put(this.binaryType, imports); 257 this.importsCounterTable.put(this.binaryType, new Integer (importsCounter)); 258 } 259 260 263 public void acceptLineSeparatorPositions(int[] positions) { 264 } 266 267 270 public void acceptPackage( 271 int declarationStart, 272 int declarationEnd, 273 char[] name) { 274 } 276 277 280 public void acceptProblem(CategorizedProblem problem) { 281 } 283 284 private void addCategories(IJavaElement element, char[][] elementCategories) { 285 if (elementCategories == null) return; 286 if (this.categories == null) 287 this.categories = new HashMap (); 288 this.categories.put(element, CharOperation.toStrings(elementCategories)); 289 } 290 291 295 public void close() { 296 this.sourceRanges = null; 297 this.parameterNames = null; 298 } 299 300 306 private String [] convertTypeNamesToSigs(char[][] typeNames) { 307 if (typeNames == null) 308 return CharOperation.NO_STRINGS; 309 int n = typeNames.length; 310 if (n == 0) 311 return CharOperation.NO_STRINGS; 312 String [] typeSigs = new String [n]; 313 for (int i = 0; i < n; ++i) { 314 char[] typeSig = Signature.createCharArrayTypeSignature(typeNames[i], false); 315 316 StringBuffer simpleTypeSig = null; 319 int start = 0; 320 int dot = -1; 321 int length = typeSig.length; 322 for (int j = 0; j < length; j++) { 323 switch (typeSig[j]) { 324 case Signature.C_UNRESOLVED: 325 if (simpleTypeSig != null) 326 simpleTypeSig.append(typeSig, start, j-start); 327 start = j; 328 break; 329 case Signature.C_DOT: 330 dot = j; 331 break; 332 case Signature.C_GENERIC_START: 333 case Signature.C_NAME_END: 334 if (dot > start) { 335 if (simpleTypeSig == null) 336 simpleTypeSig = new StringBuffer ().append(typeSig, 0, start); 337 simpleTypeSig.append(Signature.C_UNRESOLVED); 338 simpleTypeSig.append(typeSig, dot+1, j-dot-1); 339 start = j; 340 } 341 break; 342 } 343 } 344 if (simpleTypeSig == null) { 345 typeSigs[i] = new String (typeSig); 346 } else { 347 simpleTypeSig.append(typeSig, start, length-start); 348 typeSigs[i] = simpleTypeSig.toString(); 349 } 350 } 351 return typeSigs; 352 } 353 354 private synchronized void computeAllRootPaths(IType type) { 355 if (this.areRootPathsComputed) { 356 return; 357 } 358 IPackageFragmentRoot root = (IPackageFragmentRoot) type.getPackageFragment().getParent(); 359 final HashSet tempRoots = new HashSet (); 360 long time = 0; 361 if (VERBOSE) { 362 System.out.println("compute all root paths for " + root.getElementName()); time = System.currentTimeMillis(); 364 } 365 final HashSet firstLevelPackageNames = new HashSet (); 366 boolean containsADefaultPackage = false; 367 368 if (root.isArchive()) { 369 JarPackageFragmentRoot jarPackageFragmentRoot = (JarPackageFragmentRoot) root; 370 IJavaProject project = jarPackageFragmentRoot.getJavaProject(); 371 String sourceLevel = null; 372 String complianceLevel = null; 373 JavaModelManager manager = JavaModelManager.getJavaModelManager(); 374 ZipFile zip = null; 375 try { 376 zip = manager.getZipFile(jarPackageFragmentRoot.getPath()); 377 for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) { 378 ZipEntry entry = (ZipEntry ) entries.nextElement(); 379 String entryName = entry.getName(); 380 if (!entry.isDirectory()) { 381 int index = entryName.indexOf('/'); 382 if (index != -1 && Util.isClassFileName(entryName)) { 383 String firstLevelPackageName = entryName.substring(0, index); 384 if (!firstLevelPackageNames.contains(firstLevelPackageName)) { 385 if (sourceLevel == null) { 386 sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true); 387 complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true); 388 } 389 IStatus status = JavaConventions.validatePackageName(firstLevelPackageName, sourceLevel, complianceLevel); 390 if (status.isOK() || status.getSeverity() == IStatus.WARNING) { 391 firstLevelPackageNames.add(firstLevelPackageName); 392 } 393 } 394 } else if (Util.isClassFileName(entryName)) { 395 containsADefaultPackage = true; 396 } 397 } 398 } 399 } catch (CoreException e) { 400 } finally { 402 manager.closeZipFile(zip); } 404 } else { 405 Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), root.getPath(), true); 406 if (target instanceof IResource) { 407 IResource resource = (IResource) target; 408 if (resource instanceof IContainer) { 409 try { 410 IResource[] members = ((IContainer) resource).members(); 411 for (int i = 0, max = members.length; i < max; i++) { 412 IResource member = members[i]; 413 if (member.getType() == IResource.FOLDER) { 414 firstLevelPackageNames.add(member.getName()); 415 } else if (Util.isClassFileName(member.getName())) { 416 containsADefaultPackage = true; 417 } 418 } 419 } catch (CoreException e) { 420 } 422 } 423 } else if (target instanceof File ) { 424 File file = (File )target; 425 if (file.isDirectory()) { 426 File [] files = file.listFiles(); 427 for (int i = 0, max = files.length; i < max; i++) { 428 File currentFile = files[i]; 429 if (currentFile.isDirectory()) { 430 firstLevelPackageNames.add(currentFile.getName()); 431 } else if (Util.isClassFileName(currentFile.getName())) { 432 containsADefaultPackage = true; 433 } 434 } 435 } 436 } 437 } 438 439 if (Util.isArchiveFileName(this.sourcePath.lastSegment())) { 440 JavaModelManager manager = JavaModelManager.getJavaModelManager(); 441 ZipFile zip = null; 442 try { 443 zip = manager.getZipFile(this.sourcePath); 444 for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) { 445 ZipEntry entry = (ZipEntry ) entries.nextElement(); 446 String entryName; 447 if (!entry.isDirectory() && org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(entryName = entry.getName())) { 448 IPath path = new Path(entryName); 449 int segmentCount = path.segmentCount(); 450 if (segmentCount > 1) { 451 for (int i = 0, max = path.segmentCount() - 1; i < max; i++) { 452 if (firstLevelPackageNames.contains(path.segment(i))) { 453 tempRoots.add(path.uptoSegment(i)); 454 } 456 if (i == max - 1 && containsADefaultPackage) { 457 tempRoots.add(path.uptoSegment(max)); 458 } 459 } 460 } else if (containsADefaultPackage) { 461 tempRoots.add(new Path("")); } 463 } 464 } 465 } catch (CoreException e) { 466 } finally { 468 manager.closeZipFile(zip); } 470 } else { 471 Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), this.sourcePath, true); 472 if (target instanceof IResource) { 473 if (target instanceof IContainer) { 474 computeRootPath((IContainer)target, firstLevelPackageNames, containsADefaultPackage, tempRoots); 475 } 476 } else if (target instanceof File ) { 477 File file = (File )target; 478 if (file.isDirectory()) { 479 computeRootPath(file, firstLevelPackageNames, containsADefaultPackage, tempRoots); 480 } 481 } 482 } 483 int size = tempRoots.size(); 484 if (this.rootPaths != null) { 485 for (Iterator iterator = this.rootPaths.iterator(); iterator.hasNext(); ) { 486 tempRoots.add(new Path((String ) iterator.next())); 487 } 488 this.rootPaths.clear(); 489 } else { 490 this.rootPaths = new ArrayList (size); 491 } 492 size = tempRoots.size(); 493 if (size > 0) { 494 ArrayList sortedRoots = new ArrayList (tempRoots); 495 if (size > 1) { 496 Collections.sort(sortedRoots, new Comparator () { 497 public int compare(Object o1, Object o2) { 498 IPath path1 = (IPath) o1; 499 IPath path2 = (IPath) o2; 500 return path1.segmentCount() - path2.segmentCount(); 501 } 502 }); 503 } 504 for (Iterator iter = sortedRoots.iterator(); iter.hasNext();) { 505 IPath path = (IPath) iter.next(); 506 this.rootPaths.add(path.toString()); 507 } 508 } 509 this.areRootPathsComputed = true; 510 if (VERBOSE) { 511 System.out.println("Spent " + (System.currentTimeMillis() - time) + "ms"); System.out.println("Found " + size + " root paths"); int i = 0; 514 for (Iterator iterator = this.rootPaths.iterator(); iterator.hasNext();) { 515 System.out.println("root[" + i + "]=" + ((String ) iterator.next())); i++; 517 } 518 } 519 } 520 521 private void computeRootPath(File directory, HashSet firstLevelPackageNames, boolean hasDefaultPackage, Set set) { 522 File [] files = directory.listFiles(); 523 boolean hasSubDirectories = false; 524 loop: for (int i = 0, max = files.length; i < max; i++) { 525 File file = files[i]; 526 if (file.isDirectory()) { 527 hasSubDirectories = true; 528 if (firstLevelPackageNames.contains(file.getName())) { 529 IPath fullPath = new Path(file.getParentFile().getPath()); 530 IPath rootPathEntry = fullPath.removeFirstSegments(this.sourcePath.segmentCount()).setDevice(null); 531 set.add(rootPathEntry); 532 break loop; 533 } else { 534 computeRootPath(file, firstLevelPackageNames, hasDefaultPackage, set); 535 } 536 } else if (i == max - 1 && !hasSubDirectories && hasDefaultPackage) { 537 File parentDir = file.getParentFile(); 538 if (parentDir.list(FILENAME_FILTER).length != 0) { 539 IPath fullPath = new Path(parentDir.getPath()); 540 IPath rootPathEntry = fullPath.removeFirstSegments(this.sourcePath.segmentCount()).setDevice(null); 541 set.add(rootPathEntry); 542 } 543 } 544 } 545 } 546 547 private void computeRootPath(IContainer container, HashSet firstLevelPackageNames, boolean hasDefaultPackage, Set set) { 548 try { 549 IResource[] resources = container.members(); 550 boolean hasSubDirectories = false; 551 loop: for (int i = 0, max = resources.length; i < max; i++) { 552 IResource resource = resources[i]; 553 if (resource.getType() == IResource.FOLDER) { 554 hasSubDirectories = true; 555 if (firstLevelPackageNames.contains(resource.getName())) { 556 IPath fullPath = container.getFullPath(); 557 IPath rootPathEntry = fullPath.removeFirstSegments(this.sourcePath.segmentCount()).setDevice(null); 558 set.add(rootPathEntry); 559 break loop; 560 } else { 561 computeRootPath((IFolder) resource, firstLevelPackageNames, hasDefaultPackage, set); 562 } 563 } 564 if (i == max - 1 && !hasSubDirectories && hasDefaultPackage) { 565 boolean hasJavaSourceFile = false; 567 for (int j = 0; j < max; j++) { 568 if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(resources[i].getName())) { 569 hasJavaSourceFile = true; 570 break; 571 } 572 } 573 if (hasJavaSourceFile) { 574 IPath fullPath = container.getFullPath(); 575 IPath rootPathEntry = fullPath.removeFirstSegments(this.sourcePath.segmentCount()).setDevice(null); 576 set.add(rootPathEntry); 577 } 578 } 579 } 580 } catch (CoreException e) { 581 } 583 } 584 585 588 public void enterType(TypeInfo typeInfo) { 589 590 this.typeDepth++; 591 if (this.typeDepth == this.types.length) { System.arraycopy( 593 this.types, 594 0, 595 this.types = new IType[this.typeDepth * 2], 596 0, 597 this.typeDepth); 598 System.arraycopy( 599 this.typeNameRanges, 600 0, 601 this.typeNameRanges = new SourceRange[this.typeDepth * 2], 602 0, 603 this.typeDepth); 604 System.arraycopy( 605 this.typeDeclarationStarts, 606 0, 607 this.typeDeclarationStarts = new int[this.typeDepth * 2], 608 0, 609 this.typeDepth); 610 System.arraycopy( 611 this.memberName, 612 0, 613 this.memberName = new String [this.typeDepth * 2], 614 0, 615 this.typeDepth); 616 System.arraycopy( 617 this.memberDeclarationStart, 618 0, 619 this.memberDeclarationStart = new int[this.typeDepth * 2], 620 0, 621 this.typeDepth); 622 System.arraycopy( 623 this.memberNameRange, 624 0, 625 this.memberNameRange = new SourceRange[this.typeDepth * 2], 626 0, 627 this.typeDepth); 628 System.arraycopy( 629 this.methodParameterTypes, 630 0, 631 this.methodParameterTypes = new char[this.typeDepth * 2][][], 632 0, 633 this.typeDepth); 634 System.arraycopy( 635 this.methodParameterNames, 636 0, 637 this.methodParameterNames = new char[this.typeDepth * 2][][], 638 0, 639 this.typeDepth); 640 System.arraycopy( 641 this.typeModifiers, 642 0, 643 this.typeModifiers = new int[this.typeDepth * 2], 644 0, 645 this.typeDepth); 646 } 647 if (typeInfo.name.length == 0) { 648 this.anonymousCounter++; 649 if (this.anonymousCounter == this.anonymousClassName) { 650 this.types[typeDepth] = this.getType(this.binaryType.getElementName()); 651 } else { 652 this.types[typeDepth] = this.getType(new String (typeInfo.name)); 653 } 654 } else { 655 this.types[typeDepth] = this.getType(new String (typeInfo.name)); 656 } 657 this.typeNameRanges[typeDepth] = 658 new SourceRange(typeInfo.nameSourceStart, typeInfo.nameSourceEnd - typeInfo.nameSourceStart + 1); 659 this.typeDeclarationStarts[typeDepth] = typeInfo.declarationStart; 660 661 IType currentType = this.types[typeDepth]; 662 663 if (typeInfo.typeParameters != null) { 665 for (int i = 0, length = typeInfo.typeParameters.length; i < length; i++) { 666 TypeParameterInfo typeParameterInfo = typeInfo.typeParameters[i]; 667 ITypeParameter typeParameter = currentType.getTypeParameter(new String (typeParameterInfo.name)); 668 setSourceRange( 669 typeParameter, 670 new SourceRange( 671 typeParameterInfo.declarationStart, 672 typeParameterInfo.declarationEnd - typeParameterInfo.declarationStart + 1), 673 new SourceRange( 674 typeParameterInfo.nameSourceStart, 675 typeParameterInfo.nameSourceEnd - typeParameterInfo.nameSourceStart + 1)); 676 } 677 } 678 679 this.typeModifiers[typeDepth] = typeInfo.modifiers; 681 682 addCategories(currentType, typeInfo.categories); 684 } 685 686 689 public void enterCompilationUnit() { 690 } 692 693 696 public void enterConstructor(MethodInfo methodInfo) { 697 enterAbstractMethod(methodInfo); 698 } 699 700 703 public void enterField(FieldInfo fieldInfo) { 704 if (typeDepth >= 0) { 705 this.memberDeclarationStart[typeDepth] = fieldInfo.declarationStart; 706 this.memberNameRange[typeDepth] = 707 new SourceRange(fieldInfo.nameSourceStart, fieldInfo.nameSourceEnd - fieldInfo.nameSourceStart + 1); 708 String fieldName = new String (fieldInfo.name); 709 this.memberName[typeDepth] = fieldName; 710 711 IType currentType = this.types[typeDepth]; 713 IField field = currentType.getField(fieldName); 714 addCategories(field, fieldInfo.categories); 715 } 716 } 717 718 721 public void enterInitializer( 722 int declarationSourceStart, 723 int modifiers) { 724 } 726 727 730 public void enterMethod(MethodInfo methodInfo) { 731 enterAbstractMethod(methodInfo); 732 } 733 private void enterAbstractMethod(MethodInfo methodInfo) { 734 if (typeDepth >= 0) { 735 this.memberName[typeDepth] = new String (methodInfo.name); 736 this.memberNameRange[typeDepth] = 737 new SourceRange(methodInfo.nameSourceStart, methodInfo.nameSourceEnd - methodInfo.nameSourceStart + 1); 738 this.memberDeclarationStart[typeDepth] = methodInfo.declarationStart; 739 IType currentType = this.types[typeDepth]; 740 int currenTypeModifiers = this.typeModifiers[typeDepth]; 741 char[][] parameterTypes = methodInfo.parameterTypes; 742 if (parameterTypes != null && methodInfo.isConstructor && currentType.getDeclaringType() != null && !Flags.isStatic(currenTypeModifiers)) { 743 IType declaringType = currentType.getDeclaringType(); 744 String declaringTypeName = declaringType.getElementName(); 745 if (declaringTypeName.length() == 0) { 746 IClassFile classFile = declaringType.getClassFile(); 747 int length = parameterTypes.length; 748 char[][] newParameterTypes = new char[length+1][]; 749 declaringTypeName = classFile.getElementName(); 750 declaringTypeName = declaringTypeName.substring(0, declaringTypeName.indexOf('.')); 751 newParameterTypes[0] = declaringTypeName.toCharArray(); 752 System.arraycopy(parameterTypes, 0, newParameterTypes, 1, length); 753 this.methodParameterTypes[typeDepth] = newParameterTypes; 754 } else { 755 int length = parameterTypes.length; 756 char[][] newParameterTypes = new char[length+1][]; 757 newParameterTypes[0] = declaringTypeName.toCharArray(); 758 System.arraycopy(parameterTypes, 0, newParameterTypes, 1, length); 759 this.methodParameterTypes[typeDepth] = newParameterTypes; 760 } 761 } else { 762 this.methodParameterTypes[typeDepth] = parameterTypes; 763 } 764 this.methodParameterNames[typeDepth] = methodInfo.parameterNames; 765 766 IMethod method = currentType.getMethod( 767 this.memberName[typeDepth], 768 convertTypeNamesToSigs(this.methodParameterTypes[typeDepth])); 769 770 if (methodInfo.typeParameters != null) { 772 for (int i = 0, length = methodInfo.typeParameters.length; i < length; i++) { 773 TypeParameterInfo typeParameterInfo = methodInfo.typeParameters[i]; 774 ITypeParameter typeParameter = method.getTypeParameter(new String (typeParameterInfo.name)); 775 setSourceRange( 776 typeParameter, 777 new SourceRange( 778 typeParameterInfo.declarationStart, 779 typeParameterInfo.declarationEnd - typeParameterInfo.declarationStart + 1), 780 new SourceRange( 781 typeParameterInfo.nameSourceStart, 782 typeParameterInfo.nameSourceEnd - typeParameterInfo.nameSourceStart + 1)); 783 } 784 } 785 786 addCategories(method, methodInfo.categories); 788 } 789 } 790 791 794 public void exitType(int declarationEnd) { 795 if (typeDepth >= 0) { 796 IType currentType = this.types[typeDepth]; 797 setSourceRange( 798 currentType, 799 new SourceRange( 800 this.typeDeclarationStarts[typeDepth], 801 declarationEnd - this.typeDeclarationStarts[typeDepth] + 1), 802 this.typeNameRanges[typeDepth]); 803 this.typeDepth--; 804 } 805 } 806 807 810 public void exitCompilationUnit(int declarationEnd) { 811 } 813 814 817 public void exitConstructor(int declarationEnd) { 818 exitAbstractMethod(declarationEnd); 819 } 820 821 824 public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) { 825 if (typeDepth >= 0) { 826 IType currentType = this.types[typeDepth]; 827 setSourceRange( 828 currentType.getField(this.memberName[typeDepth]), 829 new SourceRange( 830 this.memberDeclarationStart[typeDepth], 831 declarationEnd - this.memberDeclarationStart[typeDepth] + 1), 832 this.memberNameRange[typeDepth]); 833 } 834 } 835 836 839 public void exitInitializer(int declarationEnd) { 840 } 842 843 846 public void exitMethod(int declarationEnd, int defaultValueStart, int defaultValueEnd) { 847 exitAbstractMethod(declarationEnd); 848 } 849 private void exitAbstractMethod(int declarationEnd) { 850 if (typeDepth >= 0) { 851 IType currentType = this.types[typeDepth]; 852 SourceRange sourceRange = 853 new SourceRange( 854 this.memberDeclarationStart[typeDepth], 855 declarationEnd - this.memberDeclarationStart[typeDepth] + 1); 856 IMethod method = currentType.getMethod( 857 this.memberName[typeDepth], 858 convertTypeNamesToSigs(this.methodParameterTypes[typeDepth])); 859 setSourceRange( 860 method, 861 sourceRange, 862 this.memberNameRange[typeDepth]); 863 setMethodParameterNames( 864 method, 865 this.methodParameterNames[typeDepth]); 866 } 867 } 868 869 874 public char[] findSource(IType type, IBinaryType info) { 875 if (!type.isBinary()) { 876 return null; 877 } 878 String simpleSourceFileName = ((BinaryType) type).getSourceFileName(info); 879 if (simpleSourceFileName == null) { 880 return null; 881 } 882 return findSource(type, simpleSourceFileName); 883 } 884 885 892 public char[] findSource(IType type, String simpleSourceFileName) { 893 long time = 0; 894 if (VERBOSE) { 895 time = System.currentTimeMillis(); 896 } 897 PackageFragment pkgFrag = (PackageFragment) type.getPackageFragment(); 898 String name = org.eclipse.jdt.internal.core.util.Util.concatWith(pkgFrag.names, simpleSourceFileName, '/'); 899 900 char[] source = null; 901 902 if (this.rootPath != null) { 903 source = getSourceForRootPath(this.rootPath, name); 904 } 905 906 if (source == null) { 907 computeAllRootPaths(type); 908 if (this.rootPaths != null) { 909 loop: for (Iterator iterator = this.rootPaths.iterator(); iterator.hasNext(); ) { 910 String currentRootPath = (String ) iterator.next(); 911 if (!currentRootPath.equals(this.rootPath)) { 912 source = getSourceForRootPath(currentRootPath, name); 913 if (source != null) { 914 this.rootPath = currentRootPath; 916 break loop; 917 } 918 } 919 } 920 } 921 } 922 if (VERBOSE) { 923 System.out.println("spent " + (System.currentTimeMillis() - time) + "ms for " + type.getElementName()); } 925 return source; 926 } 927 928 private char[] getSourceForRootPath(String currentRootPath, String name) { 929 String newFullName; 930 if (!currentRootPath.equals(IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH)) { 931 if (currentRootPath.endsWith("/")) { newFullName = currentRootPath + name; 933 } else { 934 newFullName = currentRootPath + '/' + name; 935 } 936 } else { 937 newFullName = name; 938 } 939 return this.findSource(newFullName); 940 } 941 942 public char[] findSource(String fullName) { 943 char[] source = null; 944 if (Util.isArchiveFileName(this.sourcePath.lastSegment())) { 945 ZipEntry entry = null; 947 ZipFile zip = null; 948 JavaModelManager manager = JavaModelManager.getJavaModelManager(); 949 try { 950 zip = manager.getZipFile(this.sourcePath); 951 entry = zip.getEntry(fullName); 952 if (entry != null) { 953 source = readSource(entry, zip); 955 } 956 } catch (CoreException e) { 957 return null; 958 } finally { 959 manager.closeZipFile(zip); } 961 } else { 962 Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), this.sourcePath, true); 963 if (target instanceof IResource) { 964 if (target instanceof IContainer) { 965 IResource res = ((IContainer)target).findMember(fullName); 966 if (res instanceof IFile) { 967 try { 968 source = org.eclipse.jdt.internal.core.util.Util.getResourceContentsAsCharArray((IFile)res); 969 } catch (JavaModelException e) { 970 } 972 } 973 } 974 } else if (target instanceof File ) { 975 File file = (File )target; 976 if (file.isDirectory()) { 977 File sourceFile = new File (file, fullName); 978 if (sourceFile.isFile()) { 979 try { 980 source = Util.getFileCharContent(sourceFile, this.encoding); 981 } catch (IOException e) { 982 } 984 } 985 } 986 } 987 } 988 return source; 989 } 990 991 992 993 997 public SourceRange getNameRange(IJavaElement element) { 998 switch(element.getElementType()) { 999 case IJavaElement.METHOD : 1000 if (((IMember) element).isBinary()) { 1001 IJavaElement[] el = getUnqualifiedMethodHandle((IMethod) element, false); 1002 if(el[1] != null && this.sourceRanges.get(el[0]) == null) { 1003 element = getUnqualifiedMethodHandle((IMethod) element, true)[0]; 1004 } else { 1005 element = el[0]; 1006 } 1007 } 1008 break; 1009 case IJavaElement.TYPE_PARAMETER : 1010 IJavaElement parent = element.getParent(); 1011 if (parent.getElementType() == IJavaElement.METHOD) { 1012 IMethod method = (IMethod) parent; 1013 if (method.isBinary()) { 1014 IJavaElement[] el = getUnqualifiedMethodHandle(method, false); 1015 if(el[1] != null && this.sourceRanges.get(el[0]) == null) { 1016 method = (IMethod) getUnqualifiedMethodHandle(method, true)[0]; 1017 } else { 1018 method = (IMethod) el[0]; 1019 } 1020 element = method.getTypeParameter(element.getElementName()); 1021 } 1022 } 1023 } 1024 SourceRange[] ranges = (SourceRange[]) this.sourceRanges.get(element); 1025 if (ranges == null) { 1026 return UNKNOWN_RANGE; 1027 } else { 1028 return ranges[1]; 1029 } 1030 } 1031 1032 1036 public char[][] getMethodParameterNames(IMethod method) { 1037 if (method.isBinary()) { 1038 IJavaElement[] el = getUnqualifiedMethodHandle(method, false); 1039 if(el[1] != null && this.parameterNames.get(el[0]) == null) { 1040 method = (IMethod) getUnqualifiedMethodHandle(method, true)[0]; 1041 } else { 1042 method = (IMethod) el[0]; 1043 } 1044 } 1045 char[][] parameters = (char[][]) this.parameterNames.get(method); 1046 if (parameters == null) { 1047 return null; 1048 } else { 1049 return parameters; 1050 } 1051 } 1052 1053 1057 public SourceRange getSourceRange(IJavaElement element) { 1058 switch(element.getElementType()) { 1059 case IJavaElement.METHOD : 1060 if (((IMember) element).isBinary()) { 1061 IJavaElement[] el = getUnqualifiedMethodHandle((IMethod) element, false); 1062 if(el[1] != null && this.sourceRanges.get(el[0]) == null) { 1063 element = getUnqualifiedMethodHandle((IMethod) element, true)[0]; 1064 } else { 1065 element = el[0]; 1066 } 1067 } 1068 break; 1069 case IJavaElement.TYPE_PARAMETER : 1070 IJavaElement parent = element.getParent(); 1071 if (parent.getElementType() == IJavaElement.METHOD) { 1072 IMethod method = (IMethod) parent; 1073 if (method.isBinary()) { 1074 IJavaElement[] el = getUnqualifiedMethodHandle(method, false); 1075 if(el[1] != null && this.sourceRanges.get(el[0]) == null) { 1076 method = (IMethod) getUnqualifiedMethodHandle(method, true)[0]; 1077 } else { 1078 method = (IMethod) el[0]; 1079 } 1080 element = method.getTypeParameter(element.getElementName()); 1081 } 1082 } 1083 } 1084 SourceRange[] ranges = (SourceRange[]) this.sourceRanges.get(element); 1085 if (ranges == null) { 1086 return UNKNOWN_RANGE; 1087 } else { 1088 return ranges[0]; 1089 } 1090 } 1091 1092 1096 protected IType getType(String typeName) { 1097 if (typeName.length() == 0) { 1098 IJavaElement classFile = this.binaryType.getParent(); 1099 String classFileName = classFile.getElementName(); 1100 StringBuffer newClassFileName = new StringBuffer (); 1101 int lastDollar = classFileName.lastIndexOf('$'); 1102 for (int i = 0; i <= lastDollar; i++) 1103 newClassFileName.append(classFileName.charAt(i)); 1104 newClassFileName.append(Integer.toString(this.anonymousCounter)); 1105 PackageFragment pkg = (PackageFragment) classFile.getParent(); 1106 return new BinaryType(new ClassFile(pkg, newClassFileName.toString()), typeName); 1107 } else if (this.binaryType.getElementName().equals(typeName)) 1108 return this.binaryType; 1109 else 1110 return this.binaryType.getType(typeName); 1111 } 1112 1113 1117 protected IJavaElement[] getUnqualifiedMethodHandle(IMethod method, boolean noDollar) { 1118 boolean hasDollar = false; 1119 String [] qualifiedParameterTypes = method.getParameterTypes(); 1120 String [] unqualifiedParameterTypes = new String [qualifiedParameterTypes.length]; 1121 for (int i = 0; i < qualifiedParameterTypes.length; i++) { 1122 StringBuffer unqualifiedTypeSig = new StringBuffer (); 1123 getUnqualifiedTypeSignature(qualifiedParameterTypes[i], 0, qualifiedParameterTypes[i].length(), unqualifiedTypeSig, noDollar); 1124 unqualifiedParameterTypes[i] = unqualifiedTypeSig.toString(); 1125 hasDollar |= unqualifiedParameterTypes[i].lastIndexOf('$') != -1; 1126 } 1127 1128 IJavaElement[] result = new IJavaElement[2]; 1129 result[0] = ((IType) method.getParent()).getMethod( 1130 method.getElementName(), 1131 unqualifiedParameterTypes); 1132 if(hasDollar) { 1133 result[1] = result[0]; 1134 } 1135 return result; 1136 } 1137 1138 private int getUnqualifiedTypeSignature(String qualifiedTypeSig, int start, int length, StringBuffer unqualifiedTypeSig, boolean noDollar) { 1139 char firstChar = qualifiedTypeSig.charAt(start); 1140 int end = start + 1; 1141 boolean sigStart = false; 1142 firstPass: for (int i = start; i < length; i++) { 1143 char current = qualifiedTypeSig.charAt(i); 1144 switch (current) { 1145 case Signature.C_ARRAY : 1146 case Signature.C_SUPER: 1147 case Signature.C_EXTENDS: 1148 unqualifiedTypeSig.append(current); 1149 start = i + 1; 1150 end = start + 1; 1151 firstChar = qualifiedTypeSig.charAt(start); 1152 break; 1153 case Signature.C_RESOLVED : 1154 case Signature.C_UNRESOLVED : 1155 case Signature.C_TYPE_VARIABLE : 1156 if (!sigStart) { 1157 start = ++i; 1158 sigStart = true; 1159 } 1160 break; 1161 case Signature.C_NAME_END: 1162 case Signature.C_GENERIC_START : 1163 end = i; 1164 break firstPass; 1165 case Signature.C_STAR : 1166 unqualifiedTypeSig.append(current); 1167 start = i + 1; 1168 end = start + 1; 1169 firstChar = qualifiedTypeSig.charAt(start); 1170 break; 1171 case Signature.C_GENERIC_END : 1172 return i; 1173 case Signature.C_DOT: 1174 start = ++i; 1175 break; 1176 } 1177 } 1178 switch (firstChar) { 1179 case Signature.C_RESOLVED : 1180 case Signature.C_UNRESOLVED : 1181 case Signature.C_TYPE_VARIABLE : 1182 unqualifiedTypeSig.append(Signature.C_UNRESOLVED); 1183 if (noDollar) { 1184 int lastDollar = qualifiedTypeSig.lastIndexOf('$', end); 1185 if (lastDollar > start) 1186 start = lastDollar + 1; 1187 } 1188 for (int i = start; i < length; i++) { 1189 char current = qualifiedTypeSig.charAt(i); 1190 switch (current) { 1191 case Signature.C_GENERIC_START: 1192 unqualifiedTypeSig.append(current); 1193 i++; 1194 do { 1195 i = getUnqualifiedTypeSignature(qualifiedTypeSig, i, length, unqualifiedTypeSig, noDollar); 1196 } while (qualifiedTypeSig.charAt(i) != Signature.C_GENERIC_END); 1197 unqualifiedTypeSig.append(Signature.C_GENERIC_END); 1198 break; 1199 case Signature.C_NAME_END: 1200 unqualifiedTypeSig.append(current); 1201 return i + 1; 1202 default: 1203 unqualifiedTypeSig.append(current); 1204 break; 1205 } 1206 } 1207 return length; 1208 default : 1209 unqualifiedTypeSig.append(qualifiedTypeSig.substring(start, end)); 1211 return end; 1212 } 1213 } 1214 1215 1218 public void mapSource(IType type, char[] contents, IBinaryType info) { 1219 this.mapSource(type, contents, info, null); 1220 } 1221 1222 1227 public synchronized ISourceRange mapSource( 1228 IType type, 1229 char[] contents, 1230 IBinaryType info, 1231 IJavaElement elementToFind) { 1232 1233 this.binaryType = (BinaryType) type; 1234 1235 if (this.sourceRanges.get(type) != null) return (elementToFind != null) ? getNameRange(elementToFind) : null; 1237 1238 this.importsTable.remove(this.binaryType); 1239 this.importsCounterTable.remove(this.binaryType); 1240 this.searchedElement = elementToFind; 1241 this.types = new IType[1]; 1242 this.typeDeclarationStarts = new int[1]; 1243 this.typeNameRanges = new SourceRange[1]; 1244 this.typeModifiers = new int[1]; 1245 this.typeDepth = -1; 1246 this.memberDeclarationStart = new int[1]; 1247 this.memberName = new String [1]; 1248 this.memberNameRange = new SourceRange[1]; 1249 this.methodParameterTypes = new char[1][][]; 1250 this.methodParameterNames = new char[1][][]; 1251 this.anonymousCounter = 0; 1252 1253 HashMap oldSourceRanges = (HashMap ) this.sourceRanges.clone(); 1254 try { 1255 IProblemFactory factory = new DefaultProblemFactory(); 1256 SourceElementParser parser = null; 1257 this.anonymousClassName = 0; 1258 if (info == null) { 1259 try { 1260 info = (IBinaryType) this.binaryType.getElementInfo(); 1261 } catch(JavaModelException e) { 1262 return null; 1263 } 1264 } 1265 boolean isAnonymousClass = info.isAnonymous(); 1266 char[] fullName = info.getName(); 1267 if (isAnonymousClass) { 1268 String eltName = this.binaryType.getParent().getElementName(); 1269 eltName = eltName.substring(eltName.lastIndexOf('$') + 1, eltName.length()); 1270 try { 1271 this.anonymousClassName = Integer.parseInt(eltName); 1272 } catch(NumberFormatException e) { 1273 } 1275 } 1276 boolean doFullParse = hasToRetrieveSourceRangesForLocalClass(fullName); 1277 parser = new SourceElementParser(this, factory, new CompilerOptions(this.options), doFullParse, true); 1278 parser.javadocParser.checkDocComment = false; IJavaElement javaElement = this.binaryType.getCompilationUnit(); 1280 if (javaElement == null) javaElement = this.binaryType.getParent(); 1281 parser.parseCompilationUnit( 1282 new BasicCompilationUnit(contents, null, this.binaryType.sourceFileName(info), javaElement), 1283 doFullParse); 1284 if (elementToFind != null) { 1285 ISourceRange range = this.getNameRange(elementToFind); 1286 return range; 1287 } else { 1288 return null; 1289 } 1290 } finally { 1291 if (elementToFind != null) { 1292 this.sourceRanges = oldSourceRanges; 1293 } 1294 this.binaryType = null; 1295 this.searchedElement = null; 1296 this.types = null; 1297 this.typeDeclarationStarts = null; 1298 this.typeNameRanges = null; 1299 this.typeDepth = -1; 1300 } 1301 } 1302 private char[] readSource(ZipEntry entry, ZipFile zip) { 1303 try { 1304 byte[] bytes = Util.getZipEntryByteContent(entry, zip); 1305 if (bytes != null) { 1306 return Util.bytesToChar(bytes, this.encoding); 1307 } 1308 } catch (IOException e) { 1309 } 1311 return null; 1312 } 1313 1314 1319 protected void setMethodParameterNames( 1320 IMethod method, 1321 char[][] parameterNames) { 1322 if (parameterNames == null) { 1323 parameterNames = CharOperation.NO_CHAR_CHAR; 1324 } 1325 this.parameterNames.put(method, parameterNames); 1326 } 1327 1328 1334 protected void setSourceRange( 1335 IJavaElement element, 1336 SourceRange sourceRange, 1337 SourceRange nameRange) { 1338 this.sourceRanges.put(element, new SourceRange[] { sourceRange, nameRange }); 1339 } 1340 1341 1344 public char[][] getImports(BinaryType type) { 1345 char[][] imports = (char[][]) this.importsTable.get(type); 1346 if (imports != null) { 1347 int importsCounter = ((Integer ) this.importsCounterTable.get(type)).intValue(); 1348 if (imports.length != importsCounter) { 1349 System.arraycopy( 1350 imports, 1351 0, 1352 (imports = new char[importsCounter][]), 1353 0, 1354 importsCounter); 1355 } 1356 this.importsTable.put(type, imports); 1357 } 1358 return imports; 1359 } 1360 1361 private boolean hasToRetrieveSourceRangesForLocalClass(char[] eltName) { 1362 1371 if (eltName == null) return false; 1372 int length = eltName.length; 1373 int dollarIndex = CharOperation.indexOf('$', eltName, 0); 1374 while (dollarIndex != -1) { 1375 int nameStart = dollarIndex+1; 1376 if (nameStart == length) return false; 1377 if (Character.isDigit(eltName[nameStart])) 1378 return true; 1379 dollarIndex = CharOperation.indexOf('$', eltName, nameStart); 1380 } 1381 return false; 1382 } 1383 1384} 1385 | Popular Tags |