001: /*******************************************************************************
002: * Copyright (c) 2007 IBM Corporation.
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.pde.internal.ui.search.dependencies;
011:
012: import java.util.ArrayList;
013: import java.util.HashSet;
014: import java.util.List;
015: import java.util.Set;
016: import java.util.Stack;
017:
018: import org.eclipse.core.resources.IContainer;
019: import org.eclipse.core.resources.IFile;
020: import org.eclipse.core.resources.IProject;
021: import org.eclipse.core.resources.IResource;
022: import org.eclipse.core.runtime.CoreException;
023: import org.eclipse.core.runtime.IProgressMonitor;
024: import org.eclipse.jdt.core.IClassFile;
025: import org.eclipse.jdt.core.IJavaElement;
026: import org.eclipse.jdt.core.IPackageFragment;
027: import org.eclipse.jdt.core.IPackageFragmentRoot;
028: import org.eclipse.jdt.core.JavaCore;
029: import org.eclipse.jdt.core.JavaModelException;
030: import org.eclipse.jdt.core.Signature;
031: import org.eclipse.jdt.core.ToolFactory;
032: import org.eclipse.jdt.core.util.IClassFileReader;
033: import org.eclipse.jdt.core.util.IConstantPool;
034: import org.eclipse.jdt.core.util.IConstantPoolConstant;
035: import org.eclipse.jdt.core.util.IConstantPoolEntry;
036: import org.eclipse.jdt.core.util.IExceptionAttribute;
037: import org.eclipse.jdt.core.util.IFieldInfo;
038: import org.eclipse.jdt.core.util.IMethodInfo;
039: import org.eclipse.osgi.util.ManifestElement;
040: import org.eclipse.pde.internal.core.ibundle.IBundle;
041: import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase;
042: import org.eclipse.pde.internal.ui.PDEUIMessages;
043: import org.osgi.framework.BundleException;
044: import org.osgi.framework.Constants;
045:
046: public class PackageFinder {
047:
048: public static Set findPackagesInClassFiles(IClassFile[] files,
049: IProgressMonitor monitor) {
050: Set packages = new HashSet();
051: monitor.beginTask(PDEUIMessages.PackageFinder_taskName,
052: files.length);
053: for (int i = 0; i < files.length; i++) {
054: IClassFileReader reader = ToolFactory
055: .createDefaultClassFileReader(files[i],
056: IClassFileReader.ALL);
057: if (reader != null)
058: computeReferencedTypes(reader, packages);
059: monitor.worked(1);
060: }
061: monitor.done();
062: return packages;
063: }
064:
065: static void computeReferencedTypes(IClassFileReader cfr,
066: Set packages) {
067:
068: char[][] interfaces = cfr.getInterfaceNames();
069: if (interfaces != null) {
070: for (int i = 0; i < interfaces.length; i++) {
071: //note: have to convert names like Ljava/lang/Object; to java.lang.Object
072: packages.add(getPackage(new String(interfaces[i])
073: .replace('/', '.')));
074: }
075: }
076:
077: char[] scn = cfr.getSuperclassName();
078: if (scn != null) {
079: packages.add(getPackage(new String(scn).replace('/', '.')));
080: }
081:
082: IFieldInfo[] fieldInfo = cfr.getFieldInfos();
083: for (int i = 0; i < fieldInfo.length; i++) {
084:
085: String fieldName = new String(fieldInfo[i].getDescriptor());
086: if (!isPrimitiveTypeSignature(fieldName)) {
087: String fieldDescriptor = extractFullyQualifiedType(fieldName);
088: packages.add(getPackage(new String(fieldDescriptor)));
089: }
090: }
091:
092: IMethodInfo[] methodInfo = cfr.getMethodInfos();
093: for (int i = 0; i < methodInfo.length; i++) {
094: IExceptionAttribute exceptionAttribute = methodInfo[i]
095: .getExceptionAttribute();
096: if (exceptionAttribute != null) {
097: char[][] exceptionNames = exceptionAttribute
098: .getExceptionNames();
099: for (int j = 0; j < exceptionNames.length; j++) {
100: packages.add(getPackage(new String(
101: exceptionNames[j]).replace('/', '.')));
102: }
103: }
104:
105: String descriptor = new String(methodInfo[i]
106: .getDescriptor());
107: //add parameter types
108: String[] parameterTypes = Signature
109: .getParameterTypes(descriptor);
110: for (int j = 0; j < parameterTypes.length; j++) {
111: //have to parse to convert [Ljava/lang/String; to java.lang.String
112: if (!isPrimitiveTypeSignature(parameterTypes[j])) {
113: packages
114: .add(getPackage(new String(
115: extractFullyQualifiedType(parameterTypes[j]))));
116: }
117: }
118: //add return type
119: String returnType = Signature.getReturnType(descriptor);
120: if (!isPrimitiveTypeSignature(returnType)) {
121: returnType = extractFullyQualifiedType(returnType);
122: packages.add(getPackage(returnType));
123: }
124: }
125:
126: // Is there more to extract from the constant pool??
127: IConstantPoolEntry entry;
128: IConstantPool pool = cfr.getConstantPool();
129: int length = pool.getConstantPoolCount();
130: for (int i = 1; i < length; i++) {
131: switch (pool.getEntryKind(i)) {
132: case IConstantPoolConstant.CONSTANT_Class:
133: // add reference to the class
134: entry = pool.decodeEntry(i);
135: //note: may have to convert names like Ljava/lang/Object; to java.lang.Object
136: String className = new String(entry.getClassInfoName())
137: .replace('/', '.');
138: className = className.indexOf(';') >= 0 ? extractFullyQualifiedType(className)
139: : className;
140: packages.add(getPackage(className));
141: break;
142:
143: case IConstantPoolConstant.CONSTANT_NameAndType:
144: // add reference to the name and type
145: entry = pool.decodeEntry(i);
146: int descIndex = entry
147: .getNameAndTypeInfoDescriptorIndex();
148: if (pool.getEntryKind(descIndex) == IConstantPoolConstant.CONSTANT_Utf8) {
149: entry = pool.decodeEntry(descIndex);
150: char[] type = entry.getUtf8Value();
151: if (type[0] == '(') {
152: // Method signature.
153:
154: //add parameter types
155: String descriptor = new String(type);
156: String[] parameterTypes = Signature
157: .getParameterTypes(descriptor);
158: for (int j = 0; j < parameterTypes.length; j++) {
159: if (!isPrimitiveTypeSignature(parameterTypes[j])) {
160: packages
161: .add(getPackage(extractFullyQualifiedType(parameterTypes[j])));
162: }
163: }
164: //add return type
165: String returnType = Signature
166: .getReturnType(descriptor);
167: if (!isPrimitiveTypeSignature(returnType)) {
168: returnType = extractFullyQualifiedType(returnType);
169: packages.add(getPackage(returnType));
170: }
171:
172: } else {
173: // Field type.
174: String typeString = new String(type);
175: if (!isPrimitiveTypeSignature(typeString)) {
176: packages
177: .add(getPackage(extractFullyQualifiedType(typeString)));
178: }
179: }
180: }
181: break;
182: }
183: }
184: packages.remove(""); // removes default package if it exists //$NON-NLS-1$
185: }
186:
187: static boolean isPrimitiveTypeSignature(String typeSig) {
188: //check for array of primitives
189: /* bug 101514 - changed >= 2 and typeSig.subString(1, typeSig.length) to incorporate multi dimensional arrays of primitives */
190: if (typeSig.length() >= 2
191: && typeSig.startsWith("[") && isPrimitiveTypeSignature(typeSig.substring(1, typeSig.length())))return true; //$NON-NLS-1$
192:
193: //check for primitives
194: if (typeSig.length() != 1)
195: return false;
196: if (typeSig.equals(Signature.SIG_VOID)
197: || typeSig.equals(Signature.SIG_BOOLEAN)
198: || typeSig.equals(Signature.SIG_BYTE)
199: || typeSig.equals(Signature.SIG_CHAR)
200: || typeSig.equals(Signature.SIG_DOUBLE)
201: || typeSig.equals(Signature.SIG_FLOAT)
202: || typeSig.equals(Signature.SIG_INT)
203: || typeSig.equals(Signature.SIG_LONG)
204: || typeSig.equals(Signature.SIG_SHORT)) {
205:
206: return true;
207: }
208: return false;
209: }
210:
211: static String extractFullyQualifiedType(String typeName) {
212:
213: //first convert from / to .
214: typeName = typeName.replace('/', '.');
215:
216: //hack to handle inner classes
217: if (typeName.indexOf('$') >= 0) {
218: //inner class
219: typeName = Signature.toString(typeName);
220: typeName = typeName.substring(0, typeName.lastIndexOf('.'))
221: + "$" + typeName.substring(typeName.lastIndexOf('.') + 1); //$NON-NLS-1$
222: } else {
223: //not an inner class
224: typeName = Signature.toString(typeName);
225: }
226:
227: //remove array indicator if it is there
228: typeName = typeName.endsWith("[]") ? typeName.substring(0, typeName.length() - 2) : typeName; //$NON-NLS-1$
229:
230: return typeName;
231: }
232:
233: static String getPackage(String classType) {
234: int period = classType.lastIndexOf('.');
235: return (period == -1) ? "" : classType.substring(0, period); // if no period, then we have a class in the default package, return "" for packagename //$NON-NLS-1$
236: }
237:
238: public static IClassFile[] getClassFiles(IProject project,
239: IBundlePluginModelBase base) {
240: ArrayList classFiles = new ArrayList();
241: IBundle bundle = base.getBundleModel().getBundle();
242: String value = bundle.getHeader(Constants.BUNDLE_CLASSPATH);
243: if (value == null)
244: value = "."; //$NON-NLS-1$
245: ManifestElement elems[] = null;
246: try {
247: elems = ManifestElement.parseHeader(
248: Constants.BUNDLE_CLASSPATH, value);
249: } catch (BundleException e) {
250: return new IClassFile[0];
251: }
252: for (int i = 0; i < elems.length; i++) {
253: String lib = elems[i].getValue();
254: IResource res = project.findMember(lib);
255: if (res != null) {
256: addClassFilesFromResource(res, classFiles);
257: }
258: }
259: return (IClassFile[]) classFiles
260: .toArray(new IClassFile[classFiles.size()]);
261: }
262:
263: private static void addClassFilesFromResource(IResource res,
264: List classFiles) {
265: if (res == null)
266: return;
267: Stack stack = new Stack();
268: if (res instanceof IContainer) {
269: stack.push(res);
270: while (!stack.isEmpty()) {
271: try {
272: IResource[] children = ((IContainer) stack.pop())
273: .members();
274: for (int i = 0; i < children.length; i++)
275: if (children[i] instanceof IFile
276: && "class".equals(children[i].getFileExtension())) { //$NON-NLS-1$
277: classFiles
278: .add(JavaCore
279: .createClassFileFrom((IFile) children[i]));
280: } else if (children[i] instanceof IContainer)
281: stack.push(children[i]);
282: } catch (CoreException e) {
283: }
284: }
285: } else if (res instanceof IFile) {
286: if (res.getFileExtension().equals("jar") || res.getFileExtension().equals("zip")) { //$NON-NLS-1$ //$NON-NLS-2$
287: IPackageFragmentRoot root = JavaCore.create(
288: res.getProject()).getPackageFragmentRoot(res);
289: if (root == null)
290: return;
291: try {
292: IJavaElement[] children = root.getChildren();
293: for (int i = 0; i < children.length; i++) {
294: if (children[i] instanceof IPackageFragment) {
295: IPackageFragment frag = (IPackageFragment) children[i];
296: IClassFile[] files = frag.getClassFiles();
297: for (int j = 0; j < files.length; j++)
298: classFiles.add(files[j]);
299: }
300: }
301: } catch (JavaModelException e) {
302: }
303: } else if (res.getFileExtension().equals("class")) //$NON-NLS-1$
304: JavaCore.createClassFileFrom((IFile) res);
305: }
306: }
307:
308: }
|