001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.core.search;
011:
012: import org.eclipse.core.runtime.Path;
013: import org.eclipse.jdt.core.IClassFile;
014: import org.eclipse.jdt.core.ICompilationUnit;
015: import org.eclipse.jdt.core.IJavaElement;
016: import org.eclipse.jdt.core.IPackageFragment;
017: import org.eclipse.jdt.core.IPackageFragmentRoot;
018: import org.eclipse.jdt.core.IType;
019: import org.eclipse.jdt.core.JavaModelException;
020: import org.eclipse.jdt.core.compiler.CharOperation;
021: import org.eclipse.jdt.core.search.IJavaSearchScope;
022: import org.eclipse.jdt.core.search.TypeNameMatchRequestor;
023: import org.eclipse.jdt.core.search.TypeNameRequestor;
024: import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
025: import org.eclipse.jdt.internal.core.Openable;
026: import org.eclipse.jdt.internal.core.PackageFragmentRoot;
027: import org.eclipse.jdt.internal.core.util.HandleFactory;
028: import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject;
029:
030: /**
031: * Wrapper used to link {@link IRestrictedAccessTypeRequestor} with {@link TypeNameRequestor}.
032: * This wrapper specifically allows usage of internal method {@link BasicSearchEngine#searchAllTypeNames(
033: * char[] packageName,
034: * int packageMatchRule,
035: * char[] typeName,
036: * int typeMatchRule,
037: * int searchFor,
038: * org.eclipse.jdt.core.search.IJavaSearchScope scope,
039: * IRestrictedAccessTypeRequestor nameRequestor,
040: * int waitingPolicy,
041: * org.eclipse.core.runtime.IProgressMonitor monitor) }.
042: * from API method {@link org.eclipse.jdt.core.search.SearchEngine#searchAllTypeNames(
043: * char[] packageName,
044: * int packageMatchRule,
045: * char[] typeName,
046: * int matchRule,
047: * int searchFor,
048: * org.eclipse.jdt.core.search.IJavaSearchScope scope,
049: * TypeNameRequestor nameRequestor,
050: * int waitingPolicy,
051: * org.eclipse.core.runtime.IProgressMonitor monitor) }.
052: */
053: public class TypeNameMatchRequestorWrapper implements
054: IRestrictedAccessTypeRequestor {
055: TypeNameMatchRequestor requestor;
056: private IJavaSearchScope scope; // scope is needed to retrieve project path for external resource
057: private HandleFactory handleFactory; // in case of IJavaSearchScope defined by clients, use an HandleFactory instead
058:
059: /**
060: * Cache package fragment root information to optimize speed performance.
061: */
062: private String lastPkgFragmentRootPath;
063: private IPackageFragmentRoot lastPkgFragmentRoot;
064:
065: /**
066: * Cache package handles to optimize memory.
067: */
068: private HashtableOfArrayToObject packageHandles;
069:
070: public TypeNameMatchRequestorWrapper(
071: TypeNameMatchRequestor requestor, IJavaSearchScope scope) {
072: this .requestor = requestor;
073: this .scope = scope;
074: if (!(scope instanceof JavaSearchScope)) {
075: this .handleFactory = new HandleFactory();
076: }
077: }
078:
079: /* (non-Javadoc)
080: * @see org.eclipse.jdt.internal.core.search.IRestrictedAccessTypeRequestor#acceptType(int, char[], char[], char[][], java.lang.String, org.eclipse.jdt.internal.compiler.env.AccessRestriction)
081: */
082: public void acceptType(int modifiers, char[] packageName,
083: char[] simpleTypeName, char[][] enclosingTypeNames,
084: String path, AccessRestriction access) {
085: try {
086: IType type = null;
087: if (this .handleFactory != null) {
088: Openable openable = this .handleFactory.createOpenable(
089: path, this .scope);
090: if (openable == null)
091: return;
092: switch (openable.getElementType()) {
093: case IJavaElement.COMPILATION_UNIT:
094: ICompilationUnit cu = (ICompilationUnit) openable;
095: if (enclosingTypeNames != null
096: && enclosingTypeNames.length > 0) {
097: type = cu.getType(new String(
098: enclosingTypeNames[0]));
099: for (int j = 1, l = enclosingTypeNames.length; j < l; j++) {
100: type = type.getType(new String(
101: enclosingTypeNames[j]));
102: }
103: type = type.getType(new String(simpleTypeName));
104: } else {
105: type = cu.getType(new String(simpleTypeName));
106: }
107: break;
108: case IJavaElement.CLASS_FILE:
109: type = ((IClassFile) openable).getType();
110: break;
111: }
112: } else {
113: int separatorIndex = path
114: .indexOf(IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR);
115: type = separatorIndex == -1 ? createTypeFromPath(path,
116: new String(simpleTypeName), enclosingTypeNames)
117: : createTypeFromJar(path, separatorIndex);
118: }
119: if (type != null) {
120: this .requestor
121: .acceptTypeNameMatch(new JavaSearchTypeNameMatch(
122: type, modifiers));
123: }
124: } catch (JavaModelException e) {
125: // skip
126: }
127: }
128:
129: private IType createTypeFromJar(String resourcePath,
130: int separatorIndex) throws JavaModelException {
131: // path to a class file inside a jar
132: // Optimization: cache package fragment root handle and package handles
133: if (this .lastPkgFragmentRootPath == null
134: || this .lastPkgFragmentRootPath.length() > resourcePath
135: .length()
136: || !resourcePath
137: .startsWith(this .lastPkgFragmentRootPath)) {
138: String jarPath = resourcePath.substring(0, separatorIndex);
139: IPackageFragmentRoot root = ((JavaSearchScope) this .scope)
140: .packageFragmentRoot(resourcePath);
141: if (root == null)
142: return null;
143: this .lastPkgFragmentRootPath = jarPath;
144: this .lastPkgFragmentRoot = root;
145: this .packageHandles = new HashtableOfArrayToObject(5);
146: }
147: // create handle
148: String classFilePath = resourcePath
149: .substring(separatorIndex + 1);
150: String[] simpleNames = new Path(classFilePath).segments();
151: String[] pkgName;
152: int length = simpleNames.length - 1;
153: if (length > 0) {
154: pkgName = new String[length];
155: System.arraycopy(simpleNames, 0, pkgName, 0, length);
156: } else {
157: pkgName = CharOperation.NO_STRINGS;
158: }
159: IPackageFragment pkgFragment = (IPackageFragment) this .packageHandles
160: .get(pkgName);
161: if (pkgFragment == null) {
162: pkgFragment = ((PackageFragmentRoot) this .lastPkgFragmentRoot)
163: .getPackageFragment(pkgName);
164: this .packageHandles.put(pkgName, pkgFragment);
165: }
166: return pkgFragment.getClassFile(simpleNames[length]).getType();
167: }
168:
169: private IType createTypeFromPath(String resourcePath,
170: String simpleTypeName, char[][] enclosingTypeNames)
171: throws JavaModelException {
172: // path to a file in a directory
173: // Optimization: cache package fragment root handle and package handles
174: int rootPathLength = -1;
175: if (this .lastPkgFragmentRootPath == null
176: || !(resourcePath
177: .startsWith(this .lastPkgFragmentRootPath)
178: && (rootPathLength = this .lastPkgFragmentRootPath
179: .length()) > 0 && resourcePath
180: .charAt(rootPathLength) == '/')) {
181: IPackageFragmentRoot root = ((JavaSearchScope) this .scope)
182: .packageFragmentRoot(resourcePath);
183: if (root == null)
184: return null;
185: this .lastPkgFragmentRoot = root;
186: this .lastPkgFragmentRootPath = this .lastPkgFragmentRoot
187: .getPath().toString();
188: this .packageHandles = new HashtableOfArrayToObject(5);
189: }
190: // create handle
191: resourcePath = resourcePath
192: .substring(this .lastPkgFragmentRootPath.length() + 1);
193: String[] simpleNames = new Path(resourcePath).segments();
194: String[] pkgName;
195: int length = simpleNames.length - 1;
196: if (length > 0) {
197: pkgName = new String[length];
198: System.arraycopy(simpleNames, 0, pkgName, 0, length);
199: } else {
200: pkgName = CharOperation.NO_STRINGS;
201: }
202: IPackageFragment pkgFragment = (IPackageFragment) this .packageHandles
203: .get(pkgName);
204: if (pkgFragment == null) {
205: pkgFragment = ((PackageFragmentRoot) this .lastPkgFragmentRoot)
206: .getPackageFragment(pkgName);
207: this .packageHandles.put(pkgName, pkgFragment);
208: }
209: String simpleName = simpleNames[length];
210: if (org.eclipse.jdt.internal.core.util.Util
211: .isJavaLikeFileName(simpleName)) {
212: ICompilationUnit unit = pkgFragment
213: .getCompilationUnit(simpleName);
214: int etnLength = enclosingTypeNames == null ? 0
215: : enclosingTypeNames.length;
216: IType type = (etnLength == 0) ? unit
217: .getType(simpleTypeName) : unit.getType(new String(
218: enclosingTypeNames[0]));
219: if (etnLength > 0) {
220: for (int i = 1; i < etnLength; i++) {
221: type = type.getType(new String(
222: enclosingTypeNames[i]));
223: }
224: type = type.getType(simpleTypeName);
225: }
226: return type;
227: } else {
228: IClassFile classFile = pkgFragment.getClassFile(simpleName);
229: return classFile.getType();
230: }
231: }
232: }
|