1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
14 import java.util.ArrayList;
15 import java.util.HashMap;
18 import net.sourceforge.phpdt.core.IClasspathEntry;
19 import net.sourceforge.phpdt.core.IJavaElement;
20 import net.sourceforge.phpdt.core.IJavaProject;
21 import net.sourceforge.phpdt.core.IPackageFragment;
22 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
23 import net.sourceforge.phpdt.core.IType;
24 import net.sourceforge.phpdt.core.IWorkingCopy;
25 import net.sourceforge.phpdt.core.JavaModelException;
26 import net.sourceforge.phpdt.core.ICompilationUnit;
27 import net.sourceforge.phpdt.core.JavaCore;
28 import net.sourceforge.phpdt.internal.core.util.PerThreadObject;
29 import net.sourceforge.phpdt.internal.core.util.Util;
31 import org.eclipse.core.resources.IResource;
32 import org.eclipse.core.resources.IWorkspace;
33 import org.eclipse.core.resources.ResourcesPlugin;
34 import org.eclipse.core.runtime.IPath;
36 * A <code>NameLookup</code> provides name resolution within a Java project.
37 * The name lookup facility uses the project's classpath to prioritize the
38 * order in which package fragments are searched when resolving a name.
40 * <p>Name lookup only returns a handle when the named element actually
41 * exists in the model; otherwise <code>null</code> is returned.
43 * <p>There are two logical sets of methods within this interface. Methods
44 * which start with <code>find*</code> are intended to be convenience methods for quickly
45 * finding an element within another element; for instance, for finding a class within a
46 * package. The other set of methods all begin with <code>seek*</code>. These methods
47 * do comprehensive searches of the <code>IJavaProject</code> returning hits
48 * in real time through an <code>IJavaElementRequestor</code>.
51 public class NameLookup {
53 * Accept flag for specifying classes.
55 public static final int ACCEPT_CLASSES = 0x00000002;
58 * Accept flag for specifying interfaces.
60 public static final int ACCEPT_INTERFACES = 0x00000004;
63 * The <code>IPackageFragmentRoot</code>'s associated
64 * with the classpath of this NameLookup facility's
67 protected IPackageFragmentRoot[] fPackageFragmentRoots= null;
70 * Table that maps package names to lists of package fragments for
71 * all package fragments in the package fragment roots known
72 * by this name lookup facility. To allow > 1 package fragment
73 * with the same name, values are arrays of package fragments
74 * ordered as they appear on the classpath.
76 protected Map fPackageFragments;
79 * The <code>IWorkspace</code> that this NameLookup
80 * is configure within.
82 protected IWorkspace workspace;
85 * A map from compilation unit handles to units to look inside (compilation
86 * units or working copies).
87 * Allows working copies to take precedence over compilation units.
88 * The cache is a 2-level cache, first keyed by thread.
90 protected PerThreadObject unitsToLookInside = new PerThreadObject();
92 public NameLookup(IJavaProject project) throws JavaModelException {
93 configureFromProject(project);
97 * Returns true if:<ul>
98 * <li>the given type is an existing class and the flag's <code>ACCEPT_CLASSES</code>
100 * <li>the given type is an existing interface and the <code>ACCEPT_INTERFACES</code>
102 * <li>neither the <code>ACCEPT_CLASSES</code> or <code>ACCEPT_INTERFACES</code>
105 * Otherwise, false is returned.
107 protected boolean acceptType(IType type, int acceptFlags) {
108 if (acceptFlags == 0)
109 return true; // no flags, always accepted
111 if (type.isClass()) {
112 return (acceptFlags & ACCEPT_CLASSES) != 0;
114 return (acceptFlags & ACCEPT_INTERFACES) != 0;
116 } catch (JavaModelException npe) {
117 return false; // the class is not present, do not accept.
122 * Configures this <code>NameLookup</code> based on the
123 * info of the given <code>IJavaProject</code>.
125 * @throws JavaModelException if the <code>IJavaProject</code> has no classpath.
127 private void configureFromProject(IJavaProject project) throws JavaModelException {
128 workspace= ResourcesPlugin.getWorkspace();
129 fPackageFragmentRoots= ((JavaProject) project).getAllPackageFragmentRoots();
130 fPackageFragments= new HashMap();
131 IPackageFragment[] frags = this.getPackageFragmentsInRoots(fPackageFragmentRoots, project);
132 for (int i= 0; i < frags.length; i++) {
133 IPackageFragment fragment= frags[i];
134 IPackageFragment[] entry= (IPackageFragment[]) fPackageFragments.get(fragment.getElementName());
136 entry= new IPackageFragment[1];
138 fPackageFragments.put(fragment.getElementName(), entry);
140 IPackageFragment[] copy= new IPackageFragment[entry.length + 1];
141 System.arraycopy(entry, 0, copy, 0, entry.length);
142 copy[entry.length]= fragment;
143 fPackageFragments.put(fragment.getElementName(), copy);
149 * Finds every type in the project whose simple name matches
150 * the prefix, informing the requestor of each hit. The requestor
151 * is polled for cancellation at regular intervals.
153 * <p>The <code>partialMatch</code> argument indicates partial matches
154 * should be considered.
156 private void findAllTypes(String prefix, boolean partialMatch, int acceptFlags, IJavaElementRequestor requestor) {
157 int count= fPackageFragmentRoots.length;
158 for (int i= 0; i < count; i++) {
159 if (requestor.isCanceled())
161 IPackageFragmentRoot root= fPackageFragmentRoots[i];
162 IJavaElement[] packages= null;
164 packages= root.getChildren();
165 } catch (JavaModelException npe) {
166 continue; // the root is not present, continue;
168 if (packages != null) {
169 for (int j= 0, packageCount= packages.length; j < packageCount; j++) {
170 if (requestor.isCanceled())
172 seekTypes(prefix, (IPackageFragment) packages[j], partialMatch, acceptFlags, requestor);
179 * Returns the <code>ICompilationUnit</code> which defines the type
180 * named <code>qualifiedTypeName</code>, or <code>null</code> if
181 * none exists. The domain of the search is bounded by the classpath
182 * of the <code>IJavaProject</code> this <code>NameLookup</code> was
185 * The name must be fully qualified (eg "java.lang.Object", "java.util.Hashtable$Entry")
187 public ICompilationUnit findCompilationUnit(String qualifiedTypeName) {
188 String pkgName= IPackageFragment.DEFAULT_PACKAGE_NAME;
189 String cuName= qualifiedTypeName;
191 int index= qualifiedTypeName.lastIndexOf('.');
193 pkgName= qualifiedTypeName.substring(0, index);
194 cuName= qualifiedTypeName.substring(index + 1);
196 index= cuName.indexOf('$');
198 cuName= cuName.substring(0, index);
200 cuName += ".java"; //$NON-NLS-1$
201 IPackageFragment[] frags= (IPackageFragment[]) fPackageFragments.get(pkgName);
203 for (int i= 0; i < frags.length; i++) {
204 IPackageFragment frag= frags[i];
205 // if (!(frag instanceof JarPackageFragment)) {
206 // ICompilationUnit cu= frag.getCompilationUnit(cuName);
207 // if (cu != null && cu.exists()) {
217 * Returns the package fragment whose path matches the given
218 * (absolute) path, or <code>null</code> if none exist. The domain of
219 * the search is bounded by the classpath of the <code>IJavaProject</code>
220 * this <code>NameLookup</code> was obtained from.
222 * - internal to the workbench: "/Project/src"
223 * - external to the workbench: "c:/jdk/classes.zip/java/lang"
225 public IPackageFragment findPackageFragment(IPath path) {
226 if (!path.isAbsolute()) {
227 throw new IllegalArgumentException(Util.bind("path.mustBeAbsolute")); //$NON-NLS-1$
230 * this code should rather use the package fragment map to find the candidate package, then
231 * check if the respective enclosing root maps to the one on this given IPath.
233 IResource possibleFragment = workspace.getRoot().findMember(path);
234 if (possibleFragment == null) {
236 for (int i = 0; i < fPackageFragmentRoots.length; i++) {
237 IPackageFragmentRoot root = fPackageFragmentRoots[i];
238 if (!root.isExternal()) {
241 IPath rootPath = root.getPath();
242 int matchingCount = rootPath.matchingFirstSegments(path);
243 if (matchingCount != 0) {
244 String name = path.toOSString();
245 // + 1 is for the File.separatorChar
246 name = name.substring(rootPath.toOSString().length() + 1, name.length());
247 name = name.replace(File.separatorChar, '.');
248 IJavaElement[] list = null;
250 list = root.getChildren();
251 } catch (JavaModelException npe) {
252 continue; // the package fragment root is not present;
254 int elementCount = list.length;
255 for (int j = 0; j < elementCount; j++) {
256 IPackageFragment packageFragment = (IPackageFragment) list[j];
257 if (nameMatches(name, packageFragment, false)) {
258 return packageFragment;
264 IJavaElement fromFactory = JavaCore.create(possibleFragment);
265 if (fromFactory == null) {
268 if (fromFactory instanceof IPackageFragment) {
269 return (IPackageFragment) fromFactory;
271 if (fromFactory instanceof IJavaProject) {
272 // default package in a default root
273 JavaProject project = (JavaProject) fromFactory;
275 IClasspathEntry entry = project.getClasspathEntryFor(path);
277 IPackageFragmentRoot root =
278 project.getPackageFragmentRoot(project.getResource());
279 IPackageFragment[] pkgs = (IPackageFragment[]) fPackageFragments.get(IPackageFragment.DEFAULT_PACKAGE_NAME);
283 for (int i = 0; i < pkgs.length; i++) {
284 if (pkgs[i].getParent().equals(root)) {
289 } catch (JavaModelException e) {
298 * Returns the package fragments whose name matches the given
299 * (qualified) name, or <code>null</code> if none exist.
303 * - qualified: "pack.pack1.pack2"
304 * @param partialMatch partial name matches qualify when <code>true</code>,
305 * only exact name matches qualify when <code>false</code>
307 public IPackageFragment[] findPackageFragments(String name, boolean partialMatch) {
308 int count= fPackageFragmentRoots.length;
310 name= name.toLowerCase();
311 for (int i= 0; i < count; i++) {
312 IPackageFragmentRoot root= fPackageFragmentRoots[i];
313 IJavaElement[] list= null;
315 list= root.getChildren();
316 } catch (JavaModelException npe) {
317 continue; // the package fragment root is not present;
319 int elementCount= list.length;
320 IPackageFragment[] result = new IPackageFragment[elementCount];
321 int resultLength = 0;
322 for (int j= 0; j < elementCount; j++) {
323 IPackageFragment packageFragment= (IPackageFragment) list[j];
324 if (nameMatches(name, packageFragment, true)) {
325 result[resultLength++] = packageFragment;
328 if (resultLength > 0) {
329 System.arraycopy(result, 0, result = new IPackageFragment[resultLength], 0, resultLength);
336 IPackageFragment[] fragments= (IPackageFragment[]) fPackageFragments.get(name);
337 if (fragments != null) {
338 IPackageFragment[] result = new IPackageFragment[fragments.length];
339 int resultLength = 0;
340 for (int i= 0; i < fragments.length; i++) {
341 IPackageFragment packageFragment= fragments[i];
342 result[resultLength++] = packageFragment;
344 if (resultLength > 0) {
345 System.arraycopy(result, 0, result = new IPackageFragment[resultLength], 0, resultLength);
358 public IType findType(String typeName, String packageName, boolean partialMatch, int acceptFlags) {
359 if (packageName == null) {
360 packageName= IPackageFragment.DEFAULT_PACKAGE_NAME;
362 JavaElementRequestor elementRequestor = new JavaElementRequestor();
363 seekPackageFragments(packageName, false, elementRequestor);
364 IPackageFragment[] packages= elementRequestor.getPackageFragments();
366 for (int i= 0, length= packages.length; i < length; i++) {
367 IType type= findType(typeName, packages[i], partialMatch, acceptFlags);
374 * Returns all the package fragments found in the specified
375 * package fragment roots. Make sure the returned fragments have the given
376 * project as great parent. This ensures the name lookup will not refer to another
377 * project (through jar package fragment roots)
379 private IPackageFragment[] getPackageFragmentsInRoots(IPackageFragmentRoot[] roots, IJavaProject project) {
381 // The following code assumes that all the roots have the given project as their parent
382 ArrayList frags = new ArrayList();
383 for (int i = 0; i < roots.length; i++) {
384 IPackageFragmentRoot root = roots[i];
386 IJavaElement[] children = root.getChildren();
388 /* 2 jar package fragment roots can be equals but not belonging
389 to the same project. As a result, they share the same element info.
390 So this jar package fragment root could get the children of
391 another jar package fragment root.
392 The following code ensures that the children of this jar package
393 fragment root have the given project as a great parent.
395 int length = children.length;
396 if (length == 0) continue;
397 if (children[0].getParent().getParent().equals(project)) {
398 // the children have the right parent, simply add them to the list
399 for (int j = 0; j < length; j++) {
400 frags.add(children[j]);
403 // create a new handle with the root as the parent
404 for (int j = 0; j < length; j++) {
405 frags.add(root.getPackageFragment(children[j].getElementName()));
408 } catch (JavaModelException e) {
412 IPackageFragment[] fragments = new IPackageFragment[frags.size()];
413 frags.toArray(fragments);
418 * Returns the first type in the given package whose name
419 * matches the given (unqualified) name, or <code>null</code> if none
420 * exist. Specifying a <code>null</code> package will result in no matches.
421 * The domain of the search is bounded by the Java project from which
422 * this name lookup was obtained.
424 * @param name the name of the type to find
425 * @param pkg the package to search
426 * @param partialMatch partial name matches qualify when <code>true</code>,
427 * only exact name matches qualify when <code>false</code>
428 * @param acceptFlags a bit mask describing if classes, interfaces or both classes and interfaces
429 * are desired results. If no flags are specified, all types are returned.
431 * @see #ACCEPT_CLASSES
432 * @see #ACCEPT_INTERFACES
434 public IType findType(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags) {
438 // Return first found (ignore duplicates).
439 //synchronized(JavaModelManager.getJavaModelManager()){
440 // SingleTypeRequestor typeRequestor = new SingleTypeRequestor();
441 // seekTypes(name, pkg, partialMatch, acceptFlags, typeRequestor);
442 // IType type= typeRequestor.getType();
449 * Returns the type specified by the qualified name, or <code>null</code>
450 * if none exist. The domain of
451 * the search is bounded by the Java project from which this name lookup was obtained.
453 * @param name the name of the type to find
454 * @param partialMatch partial name matches qualify when <code>true</code>,
455 * only exact name matches qualify when <code>false</code>
456 * @param acceptFlags a bit mask describing if classes, interfaces or both classes and interfaces
457 * are desired results. If no flags are specified, all types are returned.
459 * @see #ACCEPT_CLASSES
460 * @see #ACCEPT_INTERFACES
462 public IType findType(String name, boolean partialMatch, int acceptFlags) {
463 int index= name.lastIndexOf('.');
464 String className= null, packageName= null;
466 packageName= IPackageFragment.DEFAULT_PACKAGE_NAME;
469 packageName= name.substring(0, index);
470 className= name.substring(index + 1);
472 return findType(className, packageName, partialMatch, acceptFlags);
476 * Returns true if the given element's name matches the
477 * specified <code>searchName</code>, otherwise false.
479 * <p>The <code>partialMatch</code> argument indicates partial matches
480 * should be considered.
481 * NOTE: in partialMatch mode, the case will be ignored, and the searchName must already have
484 protected boolean nameMatches(String searchName, IJavaElement element, boolean partialMatch) {
486 // partial matches are used in completion mode, thus case insensitive mode
487 return element.getElementName().toLowerCase().startsWith(searchName);
489 return element.getElementName().equals(searchName);
494 * Notifies the given requestor of all package fragments with the
495 * given name. Checks the requestor at regular intervals to see if the
496 * requestor has canceled. The domain of
497 * the search is bounded by the <code>IJavaProject</code>
498 * this <code>NameLookup</code> was obtained from.
500 * @param partialMatch partial name matches qualify when <code>true</code>;
501 * only exact name matches qualify when <code>false</code>
503 public void seekPackageFragments(String name, boolean partialMatch, IJavaElementRequestor requestor) {
504 int count= fPackageFragmentRoots.length;
505 String matchName= partialMatch ? name.toLowerCase() : name;
506 for (int i= 0; i < count; i++) {
507 if (requestor.isCanceled())
509 IPackageFragmentRoot root= fPackageFragmentRoots[i];
510 IJavaElement[] list= null;
512 list= root.getChildren();
513 } catch (JavaModelException npe) {
514 continue; // this root package fragment is not present
516 int elementCount= list.length;
517 for (int j= 0; j < elementCount; j++) {
518 if (requestor.isCanceled())
520 IPackageFragment packageFragment= (IPackageFragment) list[j];
521 if (nameMatches(matchName, packageFragment, partialMatch))
522 requestor.acceptPackageFragment(packageFragment);
528 * Notifies the given requestor of all types (classes and interfaces) in the
529 * given package fragment with the given (unqualified) name.
530 * Checks the requestor at regular intervals to see if the requestor
531 * has canceled. If the given package fragment is <code>null</code>, all types in the
532 * project whose simple name matches the given name are found.
534 * @param name The name to search
535 * @param pkg The corresponding package fragment
536 * @param partialMatch partial name matches qualify when <code>true</code>;
537 * only exact name matches qualify when <code>false</code>
538 * @param acceptFlags a bit mask describing if classes, interfaces or both classes and interfaces
539 * are desired results. If no flags are specified, all types are returned.
540 * @param requestor The requestor that collects the result
542 * @see #ACCEPT_CLASSES
543 * @see #ACCEPT_INTERFACES
545 public void seekTypes(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags, IJavaElementRequestor requestor) {
547 String matchName= partialMatch ? name.toLowerCase() : name;
548 if (matchName.indexOf('.') >= 0) { //looks for member type A.B
549 matchName= matchName.replace('.', '$');
552 findAllTypes(matchName, partialMatch, acceptFlags, requestor);
555 IPackageFragmentRoot root= (IPackageFragmentRoot) pkg.getParent();
557 int packageFlavor= root.getKind();
558 switch (packageFlavor) {
559 // case IPackageFragmentRoot.K_BINARY :
560 // seekTypesInBinaryPackage(matchName, pkg, partialMatch, acceptFlags, requestor);
562 case IPackageFragmentRoot.K_SOURCE :
563 seekTypesInSourcePackage(matchName, pkg, partialMatch, acceptFlags, requestor);
568 } catch (JavaModelException e) {
574 * Performs type search in a binary package.
576 // protected void seekTypesInBinaryPackage(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags, IJavaElementRequestor requestor) {
577 // IClassFile[] classFiles= null;
579 // classFiles= pkg.getClassFiles();
580 // } catch (JavaModelException npe) {
581 // return; // the package is not present
583 // int length= classFiles.length;
585 // String unqualifiedName= name;
586 // int index= name.lastIndexOf('$');
587 // if (index != -1) {
588 // //the type name of the inner type
589 // unqualifiedName= name.substring(index + 1, name.length());
590 // // unqualifiedName is empty if the name ends with a '$' sign.
591 // // See http://dev.eclipse.org/bugs/show_bug.cgi?id=14642
592 // if ((unqualifiedName.length() > 0 && Character.isDigit(unqualifiedName.charAt(0))) || unqualifiedName.length() == 0){
593 // unqualifiedName = name;
596 // String matchName= partialMatch ? name.toLowerCase() : name;
597 // for (int i= 0; i < length; i++) {
598 // if (requestor.isCanceled())
600 // IClassFile classFile= classFiles[i];
601 // String elementName = classFile.getElementName();
602 // if (partialMatch) elementName = elementName.toLowerCase();
605 // * Must use startWith because matchName will never have the
606 // * extension ".class" and the elementName always will.
608 // if (elementName.startsWith(matchName)) {
611 // type= classFile.getType();
612 // } catch (JavaModelException npe) {
613 // continue; // the classFile is not present
615 // if (!partialMatch || (type.getElementName().length() > 0 && !Character.isDigit(type.getElementName().charAt(0)))) { //not an anonymous type
616 // if (nameMatches(unqualifiedName, type, partialMatch) && acceptType(type, acceptFlags))
617 // requestor.acceptType(type);
624 * Performs type search in a source package.
626 protected void seekTypesInSourcePackage(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags, IJavaElementRequestor requestor) {
627 ICompilationUnit[] compilationUnits = null;
629 compilationUnits = pkg.getCompilationUnits();
630 } catch (JavaModelException npe) {
631 return; // the package is not present
633 int length= compilationUnits.length;
634 String matchName = name;
635 int index= name.indexOf('$');
636 boolean potentialMemberType = false;
637 String potentialMatchName = null;
639 //the compilation unit name of the inner type
640 potentialMatchName = name.substring(0, index);
641 potentialMemberType = true;
645 * In the following, matchName will never have the extension ".java" and
646 * the compilationUnits always will. So add it if we're looking for
649 String unitName = partialMatch ? matchName.toLowerCase() : matchName + ".java"; //$NON-NLS-1$
650 String potentialUnitName = null;
651 if (potentialMemberType) {
652 potentialUnitName = partialMatch ? potentialMatchName.toLowerCase() : potentialMatchName + ".java"; //$NON-NLS-1$
655 for (int i= 0; i < length; i++) {
656 if (requestor.isCanceled())
658 ICompilationUnit compilationUnit= compilationUnits[i];
660 // unit to look inside
661 ICompilationUnit unitToLookInside = null;
662 Map workingCopies = (Map) this.unitsToLookInside.getCurrent();
663 if (workingCopies != null
664 && (unitToLookInside = (ICompilationUnit)workingCopies.get(compilationUnit)) != null){
665 compilationUnit = unitToLookInside;
667 if ((unitToLookInside != null && !potentialMemberType) || nameMatches(unitName, compilationUnit, partialMatch)) {
670 types= compilationUnit.getTypes();
671 } catch (JavaModelException npe) {
672 continue; // the compilation unit is not present
674 int typeLength= types.length;
675 for (int j= 0; j < typeLength; j++) {
676 if (requestor.isCanceled())
678 IType type= types[j];
679 if (nameMatches(matchName, type, partialMatch)) {
680 if (acceptType(type, acceptFlags)) requestor.acceptType(type);
683 } else if (potentialMemberType && nameMatches(potentialUnitName, compilationUnit, partialMatch)) {
686 types= compilationUnit.getTypes();
687 } catch (JavaModelException npe) {
688 continue; // the compilation unit is not present
690 int typeLength= types.length;
691 for (int j= 0; j < typeLength; j++) {
692 if (requestor.isCanceled())
694 IType type= types[j];
695 if (nameMatches(potentialMatchName, type, partialMatch)) {
696 seekQualifiedMemberTypes(name.substring(index + 1, name.length()), type, partialMatch, requestor, acceptFlags);
704 * Remembers a set of compilation units that will be looked inside
705 * when looking up a type. If they are working copies, they take
706 * precedence of their compilation units.
707 * <code>null</code> means that no special compilation units should be used.
709 public void setUnitsToLookInside(IWorkingCopy[] unitsToLookInside) {
711 if (unitsToLookInside == null) {
712 this.unitsToLookInside.setCurrent(null);
714 HashMap workingCopies = new HashMap();
715 this.unitsToLookInside.setCurrent(workingCopies);
716 for (int i = 0, length = unitsToLookInside.length; i < length; i++) {
717 IWorkingCopy unitToLookInside = unitsToLookInside[i];
718 ICompilationUnit original = (ICompilationUnit)unitToLookInside.getOriginalElement();
719 if (original != null) {
720 workingCopies.put(original, unitToLookInside);
722 workingCopies.put(unitToLookInside, unitToLookInside);
729 * Notifies the given requestor of all types (classes and interfaces) in the
730 * given type with the given (possibly qualified) name. Checks
731 * the requestor at regular intervals to see if the requestor
734 * @param partialMatch partial name matches qualify when <code>true</code>,
735 * only exact name matches qualify when <code>false</code>
737 protected void seekQualifiedMemberTypes(String qualifiedName, IType type, boolean partialMatch, IJavaElementRequestor requestor, int acceptFlags) {
742 types= type.getTypes();
743 } catch (JavaModelException npe) {
744 return; // the enclosing type is not present
746 String matchName= qualifiedName;
747 int index= qualifiedName.indexOf('$');
748 boolean nested= false;
750 matchName= qualifiedName.substring(0, index);
753 int length= types.length;
754 for (int i= 0; i < length; i++) {
755 if (requestor.isCanceled())
757 IType memberType= types[i];
758 if (nameMatches(matchName, memberType, partialMatch))
760 seekQualifiedMemberTypes(qualifiedName.substring(index + 1, qualifiedName.length()), memberType, partialMatch, requestor, acceptFlags);
762 if (acceptType(memberType, acceptFlags)) requestor.acceptMemberType(memberType);