1 11 package org.eclipse.jdt.internal.core.search; 12 13 import java.util.ArrayList ; 14 import java.util.HashSet ; 15 import java.util.Map ; 16 17 import org.eclipse.core.resources.IProject; 18 import org.eclipse.core.resources.IResource; 19 import org.eclipse.core.resources.ResourcesPlugin; 20 import org.eclipse.core.runtime.IPath; 21 import org.eclipse.core.runtime.Path; 22 import org.eclipse.jdt.core.IClasspathContainer; 23 import org.eclipse.jdt.core.IClasspathEntry; 24 import org.eclipse.jdt.core.IJavaElement; 25 import org.eclipse.jdt.core.IJavaElementDelta; 26 import org.eclipse.jdt.core.IJavaModel; 27 import org.eclipse.jdt.core.IJavaProject; 28 import org.eclipse.jdt.core.IMember; 29 import org.eclipse.jdt.core.IPackageFragmentRoot; 30 import org.eclipse.jdt.core.JavaCore; 31 import org.eclipse.jdt.core.JavaModelException; 32 import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; 33 import org.eclipse.jdt.internal.core.ClasspathEntry; 34 import org.eclipse.jdt.internal.core.JavaElement; 35 import org.eclipse.jdt.internal.core.JavaModel; 36 import org.eclipse.jdt.internal.core.JavaModelManager; 37 import org.eclipse.jdt.internal.core.JavaProject; 38 import org.eclipse.jdt.internal.core.PackageFragment; 39 import org.eclipse.jdt.internal.core.util.Util; 40 41 44 public class JavaSearchScope extends AbstractSearchScope { 45 46 private ArrayList elements; 47 48 51 private ArrayList projectPaths = new ArrayList (); private int[] projectIndexes; private String [] containerPaths; private String [] relativePaths; private boolean[] isPkgPath; protected AccessRuleSet[] pathRestrictions; 57 private int pathsCount; 58 private int threshold; 59 60 private IPath[] enclosingProjectsAndJars; 61 public final static AccessRuleSet NOT_ENCLOSED = new AccessRuleSet(null, null); 62 63 public JavaSearchScope() { 64 this(5); 65 } 66 67 private JavaSearchScope(int size) { 68 initialize(size); 69 70 } 73 74 private void addEnclosingProjectOrJar(IPath path) { 75 int length = this.enclosingProjectsAndJars.length; 76 for (int i = 0; i < length; i++) { 77 if (this.enclosingProjectsAndJars[i].equals(path)) return; 78 } 79 System.arraycopy( 80 this.enclosingProjectsAndJars, 81 0, 82 this.enclosingProjectsAndJars = new IPath[length+1], 83 0, 84 length); 85 this.enclosingProjectsAndJars[length] = path; 86 } 87 88 92 public void add(JavaProject project, int includeMask, HashSet visitedProject) throws JavaModelException { 93 add(project, null, includeMask, visitedProject, null); 94 } 95 106 void add(JavaProject javaProject, IPath pathToAdd, int includeMask, HashSet visitedProjects, IClasspathEntry referringEntry) throws JavaModelException { 107 IProject project = javaProject.getProject(); 108 if (!project.isAccessible() || !visitedProjects.add(project)) return; 109 110 IPath projectPath = project.getFullPath(); 111 String projectPathString = projectPath.toString(); 112 this.addEnclosingProjectOrJar(projectPath); 113 114 IClasspathEntry[] entries = javaProject.getResolvedClasspath(); 115 IJavaModel model = javaProject.getJavaModel(); 116 JavaModelManager.PerProjectInfo perProjectInfo = javaProject.getPerProjectInfo(); 117 for (int i = 0, length = entries.length; i < length; i++) { 118 IClasspathEntry entry = entries[i]; 119 AccessRuleSet access = null; 120 ClasspathEntry cpEntry = (ClasspathEntry) entry; 121 if (referringEntry != null) { 122 if (!entry.isExported() && entry.getEntryKind() != IClasspathEntry.CPE_SOURCE) continue; 125 cpEntry = cpEntry.combineWith((ClasspathEntry)referringEntry); 126 } 128 access = cpEntry.getAccessRuleSet(); 129 switch (entry.getEntryKind()) { 130 case IClasspathEntry.CPE_LIBRARY: 131 IClasspathEntry rawEntry = null; 132 Map rootPathToRawEntries = perProjectInfo.rootPathToRawEntries; 133 if (rootPathToRawEntries != null) { 134 rawEntry = (IClasspathEntry) rootPathToRawEntries.get(entry.getPath()); 135 } 136 if (rawEntry == null) break; 137 switch (rawEntry.getEntryKind()) { 138 case IClasspathEntry.CPE_LIBRARY: 139 case IClasspathEntry.CPE_VARIABLE: 140 if ((includeMask & APPLICATION_LIBRARIES) != 0) { 141 IPath path = entry.getPath(); 142 if (pathToAdd == null || pathToAdd.equals(path)) { 143 String pathToString = path.getDevice() == null ? path.toString() : path.toOSString(); 144 add(projectPath.toString(), "", pathToString, false, access); addEnclosingProjectOrJar(path); 146 } 147 } 148 break; 149 case IClasspathEntry.CPE_CONTAINER: 150 IClasspathContainer container = JavaCore.getClasspathContainer(rawEntry.getPath(), javaProject); 151 if (container == null) break; 152 if ((container.getKind() == IClasspathContainer.K_APPLICATION && (includeMask & APPLICATION_LIBRARIES) != 0) 153 || (includeMask & SYSTEM_LIBRARIES) != 0) { 154 IPath path = entry.getPath(); 155 if (pathToAdd == null || pathToAdd.equals(path)) { 156 String pathToString = path.getDevice() == null ? path.toString() : path.toOSString(); 157 add(projectPath.toString(), "", pathToString, false, access); addEnclosingProjectOrJar(path); 159 } 160 } 161 break; 162 } 163 break; 164 case IClasspathEntry.CPE_PROJECT: 165 if ((includeMask & REFERENCED_PROJECTS) != 0) { 166 IPath path = entry.getPath(); 167 if (pathToAdd == null || pathToAdd.equals(path)) { 168 add((JavaProject) model.getJavaProject(entry.getPath().lastSegment()), null, includeMask, visitedProjects, cpEntry); 169 } 170 } 171 break; 172 case IClasspathEntry.CPE_SOURCE: 173 if ((includeMask & SOURCES) != 0) { 174 IPath path = entry.getPath(); 175 if (pathToAdd == null || pathToAdd.equals(path)) { 176 add(projectPath.toString(), Util.relativePath(path,1), projectPathString, false, access); 177 } 178 } 179 break; 180 } 181 } 182 } 183 188 public void add(IJavaElement element) throws JavaModelException { 189 IPath containerPath = null; 190 String containerPathToString = null; 191 int includeMask = SOURCES | APPLICATION_LIBRARIES | SYSTEM_LIBRARIES; 192 switch (element.getElementType()) { 193 case IJavaElement.JAVA_MODEL: 194 break; 196 case IJavaElement.JAVA_PROJECT: 197 add((JavaProject)element, null, includeMask, new HashSet (2), null); 198 break; 199 case IJavaElement.PACKAGE_FRAGMENT_ROOT: 200 IPackageFragmentRoot root = (IPackageFragmentRoot)element; 201 IPath rootPath = root.getPath(); 202 containerPath = root.getKind() == IPackageFragmentRoot.K_SOURCE ? root.getParent().getPath() : rootPath; 203 containerPathToString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString(); 204 IResource rootResource = root.getResource(); 205 String projectPath = root.getJavaProject().getPath().toString(); 206 if (rootResource != null && rootResource.isAccessible()) { 207 String relativePath = Util.relativePath(rootResource.getFullPath(), containerPath.segmentCount()); 208 add(projectPath, relativePath, containerPathToString, false, null); 209 } else { 210 add(projectPath, "", containerPathToString, false, null); } 212 break; 213 case IJavaElement.PACKAGE_FRAGMENT: 214 root = (IPackageFragmentRoot)element.getParent(); 215 projectPath = root.getJavaProject().getPath().toString(); 216 if (root.isArchive()) { 217 String relativePath = Util.concatWith(((PackageFragment) element).names, '/'); 218 containerPath = root.getPath(); 219 containerPathToString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString(); 220 add(projectPath, relativePath, containerPathToString, true, null); 221 } else { 222 IResource resource = element.getResource(); 223 if (resource != null) { 224 if (resource.isAccessible()) { 225 containerPath = root.getKind() == IPackageFragmentRoot.K_SOURCE ? root.getParent().getPath() : root.getPath(); 226 } else { 227 containerPath = resource.getParent().getFullPath(); 229 } 230 containerPathToString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString(); 231 String relativePath = Util.relativePath(resource.getFullPath(), containerPath.segmentCount()); 232 add(projectPath, relativePath, containerPathToString, true, null); 233 } 234 } 235 break; 236 default: 237 if (element instanceof IMember) { 239 if (this.elements == null) { 240 this.elements = new ArrayList (); 241 } 242 this.elements.add(element); 243 } 244 root = (IPackageFragmentRoot) element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); 245 projectPath = root.getJavaProject().getPath().toString(); 246 String relativePath; 247 if (root.getKind() == IPackageFragmentRoot.K_SOURCE) { 248 containerPath = root.getParent().getPath(); 249 relativePath = Util.relativePath(getPath(element, false), 1); 250 } else { 251 containerPath = root.getPath(); 252 relativePath = getPath(element, true).toString(); 253 } 254 containerPathToString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString(); 255 add(projectPath, relativePath, containerPathToString, false, null); 256 } 257 258 if (containerPath != null) 259 addEnclosingProjectOrJar(containerPath); 260 } 261 262 266 private void add(String projectPath, String relativePath, String containerPath, boolean isPackage, AccessRuleSet access) { 267 containerPath = normalize(containerPath); 269 relativePath = normalize(relativePath); 270 int length = this.containerPaths.length, 271 index = (containerPath.hashCode()& 0x7FFFFFFF) % length; 272 String currentRelativePath, currentContainerPath; 273 while ((currentRelativePath = this.relativePaths[index]) != null && (currentContainerPath = this.containerPaths[index]) != null) { 274 if (currentRelativePath.equals(relativePath) && currentContainerPath.equals(containerPath)) 275 return; 276 if (++index == length) { 277 index = 0; 278 } 279 } 280 int idx = this.projectPaths.indexOf(projectPath); 281 if (idx == -1) { 282 this.projectPaths.add(projectPath); 284 idx = this.projectPaths.indexOf(projectPath); 285 } 286 this.projectIndexes[index] = idx; 287 this.relativePaths[index] = relativePath; 288 this.containerPaths[index] = containerPath; 289 this.isPkgPath[index] = isPackage; 290 if (this.pathRestrictions != null) 291 this.pathRestrictions[index] = access; 292 else if (access != null) { 293 this.pathRestrictions = new AccessRuleSet[this.relativePaths.length]; 294 this.pathRestrictions[index] = access; 295 } 296 297 if (++this.pathsCount > this.threshold) 299 rehash(); 300 } 301 302 313 public boolean encloses(String resourcePathString) { 314 int separatorIndex = resourcePathString.indexOf(JAR_FILE_ENTRY_SEPARATOR); 315 if (separatorIndex != -1) { 316 String jarPath = resourcePathString.substring(0, separatorIndex); 318 String relativePath = resourcePathString.substring(separatorIndex+1); 319 return indexOf(jarPath, relativePath) >= 0; 320 } 321 return indexOf(resourcePathString) >= 0; 323 } 324 325 333 private int indexOf(String fullPath) { 334 for (int i = 0, length = this.relativePaths.length; i < length; i++) { 337 String currentRelativePath = this.relativePaths[i]; 338 if (currentRelativePath == null) continue; 339 String currentContainerPath = this.containerPaths[i]; 340 String currentFullPath = currentRelativePath.length() == 0 ? currentContainerPath : (currentContainerPath + '/' + currentRelativePath); 341 if (encloses(currentFullPath, fullPath, i)) 342 return i; 343 } 344 return -1; 345 } 346 347 361 private int indexOf(String containerPath, String relativePath) { 362 int length = this.containerPaths.length, 364 index = (containerPath.hashCode()& 0x7FFFFFFF) % length; 365 String currentContainerPath; 366 while ((currentContainerPath = this.containerPaths[index]) != null) { 367 if (currentContainerPath.equals(containerPath)) { 368 String currentRelativePath = this.relativePaths[index]; 369 if (encloses(currentRelativePath, relativePath, index)) 370 return index; 371 } 372 if (++index == length) { 373 index = 0; 374 } 375 } 376 return -1; 377 } 378 379 382 private boolean encloses(String enclosingPath, String path, int index) { 383 path = normalize(path); 385 386 int pathLength = path.length(); 387 int enclosingLength = enclosingPath.length(); 388 if (pathLength < enclosingLength) { 389 return false; 390 } 391 if (enclosingLength == 0) { 392 return true; 393 } 394 if (pathLength == enclosingLength) { 395 return path.equals(enclosingPath); 396 } 397 if (!this.isPkgPath[index]) { 398 return path.startsWith(enclosingPath) 399 && path.charAt(enclosingLength) == '/'; 400 } else { 401 if (path.startsWith(enclosingPath) 405 && ((enclosingPath.length() == path.lastIndexOf('/')) 406 || (enclosingPath.length() == path.length()))) { 407 return true; 408 } 409 } 410 return false; 411 } 412 413 416 public boolean encloses(IJavaElement element) { 417 if (this.elements != null) { 418 for (int i = 0, length = this.elements.size(); i < length; i++) { 419 IJavaElement scopeElement = (IJavaElement)this.elements.get(i); 420 IJavaElement searchedElement = element; 421 while (searchedElement != null) { 422 if (searchedElement.equals(scopeElement)) 423 return true; 424 searchedElement = searchedElement.getParent(); 425 } 426 } 427 return false; 428 } 429 IPackageFragmentRoot root = (IPackageFragmentRoot) element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); 430 if (root != null && root.isArchive()) { 431 IPath rootPath = root.getPath(); 433 String rootPathToString = rootPath.getDevice() == null ? rootPath.toString() : rootPath.toOSString(); 434 IPath relativePath = getPath(element, true); 435 return indexOf(rootPathToString, relativePath.toString()) >= 0; 436 } 437 String fullResourcePathString = getPath(element, false).toString(); 439 return indexOf(fullResourcePathString) >= 0; 440 } 441 442 445 public IPath[] enclosingProjectsAndJars() { 446 return this.enclosingProjectsAndJars; 447 } 448 private IPath getPath(IJavaElement element, boolean relativeToRoot) { 449 switch (element.getElementType()) { 450 case IJavaElement.JAVA_MODEL: 451 return Path.EMPTY; 452 case IJavaElement.JAVA_PROJECT: 453 return element.getPath(); 454 case IJavaElement.PACKAGE_FRAGMENT_ROOT: 455 if (relativeToRoot) 456 return Path.EMPTY; 457 return element.getPath(); 458 case IJavaElement.PACKAGE_FRAGMENT: 459 String relativePath = Util.concatWith(((PackageFragment) element).names, '/'); 460 return getPath(element.getParent(), relativeToRoot).append(new Path(relativePath)); 461 case IJavaElement.COMPILATION_UNIT: 462 case IJavaElement.CLASS_FILE: 463 return getPath(element.getParent(), relativeToRoot).append(new Path(element.getElementName())); 464 default: 465 return getPath(element.getParent(), relativeToRoot); 466 } 467 } 468 469 475 public AccessRuleSet getAccessRuleSet(String relativePath, String containerPath) { 476 int index = indexOf(containerPath, relativePath); 477 if (index == -1) { 478 return NOT_ENCLOSED; 480 } 481 if (this.pathRestrictions == null) 482 return null; 483 return this.pathRestrictions[index]; 484 } 485 486 protected void initialize(int size) { 487 this.pathsCount = 0; 488 this.threshold = size; int extraRoom = (int) (size * 1.75f); 490 if (this.threshold == extraRoom) 491 extraRoom++; 492 this.relativePaths = new String [extraRoom]; 493 this.containerPaths = new String [extraRoom]; 494 this.projectPaths = new ArrayList (); 495 this.projectIndexes = new int[extraRoom]; 496 this.isPkgPath = new boolean[extraRoom]; 497 this.pathRestrictions = null; 499 this.enclosingProjectsAndJars = new IPath[0]; 500 } 501 502 505 private String normalize(String path) { 506 int pathLength = path.length(); 507 int index = pathLength-1; 508 while (index >= 0 && path.charAt(index) == '/') 509 index--; 510 if (index != pathLength-1) 511 return path.substring(0, index + 1); 512 return path; 513 } 514 515 518 public void processDelta(IJavaElementDelta delta) { 519 switch (delta.getKind()) { 520 case IJavaElementDelta.CHANGED: 521 IJavaElementDelta[] children = delta.getAffectedChildren(); 522 for (int i = 0, length = children.length; i < length; i++) { 523 IJavaElementDelta child = children[i]; 524 this.processDelta(child); 525 } 526 break; 527 case IJavaElementDelta.REMOVED: 528 IJavaElement element = delta.getElement(); 529 if (this.encloses(element)) { 530 if (this.elements != null) { 531 this.elements.remove(element); 532 } 533 IPath path = null; 534 switch (element.getElementType()) { 535 case IJavaElement.JAVA_PROJECT: 536 path = ((IJavaProject)element).getProject().getFullPath(); 537 case IJavaElement.PACKAGE_FRAGMENT_ROOT: 538 if (path == null) { 539 path = ((IPackageFragmentRoot)element).getPath(); 540 } 541 int toRemove = -1; 542 for (int i = 0; i < this.pathsCount; i++) { 543 if (this.relativePaths[i].equals(path)) { toRemove = i; 545 break; 546 } 547 } 548 if (toRemove != -1) { 549 this.relativePaths[toRemove] = null; 550 rehash(); 551 } 552 } 553 } 554 break; 555 } 556 } 557 558 565 public IPackageFragmentRoot packageFragmentRoot(String resourcePathString) { 566 int index = -1; 567 int separatorIndex = resourcePathString.indexOf(JAR_FILE_ENTRY_SEPARATOR); 568 boolean isJarFile = separatorIndex != -1; 569 if (isJarFile) { 570 String jarPath = resourcePathString.substring(0, separatorIndex); 572 String relativePath = resourcePathString.substring(separatorIndex+1); 573 index = indexOf(jarPath, relativePath); 574 } else { 575 index = indexOf(resourcePathString); 577 } 578 if (index >= 0) { 579 int idx = projectIndexes[index]; 580 String projectPath = idx == -1 ? null : (String ) this.projectPaths.get(idx); 581 if (projectPath != null) { 582 IJavaProject project =JavaCore.create(ResourcesPlugin.getWorkspace().getRoot().getProject(projectPath)); 583 if (isJarFile) { 584 return project.getPackageFragmentRoot(this.containerPaths[index]); 585 } 586 Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), new Path(this.containerPaths[index]+'/'+this.relativePaths[index]), false); 587 if (target instanceof IProject) { 588 return project.getPackageFragmentRoot((IProject) target); 589 } 590 if (target instanceof IResource) { 591 IJavaElement element = JavaCore.create((IResource)target); 592 return (IPackageFragmentRoot) element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); 593 } 594 } 595 } 596 return null; 597 } 598 599 private void rehash() { 600 JavaSearchScope newScope = new JavaSearchScope(this.pathsCount * 2); newScope.projectPaths.ensureCapacity(this.projectPaths.size()); 602 String currentPath; 603 for (int i = this.relativePaths.length; --i >= 0;) 604 if ((currentPath = this.relativePaths[i]) != null) { 605 int idx = this.projectIndexes[i]; 606 String projectPath = idx == -1 ? null : (String )this.projectPaths.get(idx); 607 newScope.add(projectPath, currentPath, this.containerPaths[i], this.isPkgPath[i], this.pathRestrictions == null ? null : this.pathRestrictions[i]); 608 } 609 610 this.relativePaths = newScope.relativePaths; 611 this.containerPaths = newScope.containerPaths; 612 this.projectPaths = newScope.projectPaths; 613 this.projectIndexes = newScope.projectIndexes; 614 this.isPkgPath = newScope.isPkgPath; 615 this.pathRestrictions = newScope.pathRestrictions; 616 this.threshold = newScope.threshold; 617 } 618 619 public String toString() { 620 StringBuffer result = new StringBuffer ("JavaSearchScope on "); if (this.elements != null) { 622 result.append("["); for (int i = 0, length = this.elements.size(); i < length; i++) { 624 JavaElement element = (JavaElement)this.elements.get(i); 625 result.append("\n\t"); result.append(element.toStringWithAncestors()); 627 } 628 result.append("\n]"); } else { 630 if (this.pathsCount == 0) { 631 result.append("[empty scope]"); } else { 633 result.append("["); for (int i = 0; i < this.relativePaths.length; i++) { 635 String path = this.relativePaths[i]; 636 if (path == null) continue; 637 result.append("\n\t"); result.append(this.containerPaths[i]); 639 if (path.length() > 0) { 640 result.append('/'); 641 result.append(path); 642 } 643 } 644 result.append("\n]"); } 646 } 647 return result.toString(); 648 } 649 } 650 | Popular Tags |